9

I have a model project_phase:

    from django.db import models
    from django.utils import simplejson
    from core.models import pmo_review_task

it references pmo_review_task (because it creates a pmo_review_task in its save ovewrite)

from django.db import models
from datetime import datetime
from django.contrib.auth.models import User
from core.models import sc_review_task

which references sc_review_task that references project_phase (because it creates a project_phase in its save ovewrite)

from django.db import models
from core.models import project_phase

so it ends up project_phase imports pmo_review_task imports sc_review_task imports project_phase and I guess it loops up somehow generating this error:

Unhandled exception in thread started by <bound method Command.inner_run of <django.core.management.commands.runserver.Command object at 0x010ACFB0>>
Traceback (most recent call last):
  File "C:\Python27\lib\site-packages\django\core\management\commands\runserver.py", line 88, in inner_run
    self.validate(display_num_errors=True)
  File "C:\Python27\lib\site-packages\django\core\management\base.py", line 249, in validate
    num_errors = get_validation_errors(s, app)
  File "C:\Python27\lib\site-packages\django\core\management\validation.py", line 35, in get_validation_errors
    for (app_name, error) in get_app_errors().items():
  File "C:\Python27\lib\site-packages\django\db\models\loading.py", line 146, in get_app_errors
    self._populate()
  File "C:\Python27\lib\site-packages\django\db\models\loading.py", line 64, in _populate
    self.load_app(app_name)
  File "C:\Python27\lib\site-packages\django\db\models\loading.py", line 78, in load_app
    models = import_module('.models', app_name)
  File "C:\Python27\lib\site-packages\django\utils\importlib.py", line 35, in import_module
    __import__(name)
  File "C:\work\Portman\core\models\__init__.py", line 4, in <module>
    from pmo_review_task import pmo_review_task
  File "C:\work\Portman\core\models\pmo_review_task.py", line 5, in <module>
    from core.models import sc_review_task
  File "C:\work\Portman\core\models\sc_review_task.py", line 3, in <module>
    from core.models import project_phase
  File "C:\work\Portman\core\models\project_phase.py", line 4, in <module>
    from core.models import pmo_review_task
ImportError: cannot import name pmo_review_task

how do I overcome this?

abolotnov
  • 4,282
  • 9
  • 56
  • 88
  • Why are these three models in separate files? Are you trying to have a "one-model-per-file" kind of architecture? Why? – S.Lott Feb 17 '12 at 10:55

3 Answers3

20

Two ways:

  1. To import a model inside a method (as @YujiTomita suggested).
  2. To use get_model function from django.db.models which is designed for lazy model imports.:

    project_phase = get_model('core', 'project_phase')
    

I prefer the second one, but both methods are ok.

DrTyrsa
  • 31,014
  • 7
  • 86
  • 86
  • Yes, I suppose this is the more appropriate answer since the question title specifically mentions django model recursive imports. +1 – Yuji 'Tomita' Tomita Feb 17 '12 at 07:57
  • Is first way more expensive? I mean there will be import every function call. – sunprophit Nov 08 '13 at 14:05
  • @sunprophit I can't say which of them if more "expensive", as cost of any of these methods will be negligible (comparing to other operations in your code like communicating with DB). Readability or your personal taste are more valuable factors here. – DrTyrsa Nov 08 '13 at 21:29
7

import project_phase inside the save method.

The import is called whenever the code is executed.

If it's in the global module namespace (at the top) then it's called right away and you'll have circular import problems as you describe because one file imports another file which imports the original file.

If you put the problem import statement inside a function, it is /not/ called upon importing the file.

import foo # executed upon importing this file. 

def import_foo_when_called():
    import foo # only executed when function is called, thus no problems when 
               # another module imports this file.
Yuji 'Tomita' Tomita
  • 115,817
  • 29
  • 282
  • 245
3

Django 1.9 and above

As get_model() in django.db.models has been removed in 1.9.

Use django.apps.get_model()

Similar Question: What is the equivalent of django.db.models.loading.get_model() in Django 1.9?

or use application label in quotes if you are just using it to create foreignkey.

Instead of from core.models import project_phase do

models.ForeignKey("core.project_phase")
Nagashayan
  • 2,487
  • 2
  • 18
  • 22