The cause of the import error is easily found, in the backtrace of the ImportError exception.
When you look in the backtrace, you'll see that the module has been imported before. One of it's imports imported something else, executed main code, and now imports that first module. Since the first module was not fully initialized (it was still stuck at it's import code), you now get errors of symbols not found. Which makes sense, because the main code of the module didn't reach that point yet.
Common causes in Django are:
Importing a subpackage from a totally different module,
e.g. from mymodule.admin.utils import ...
This will load admin/__init__.py
first, which likely imports a while load of other packages (e.g. models, admin views). The admin view gets initialized with admin.site.register(..)
so the constructor could start importing more stuff. At some point that might hit your module issuing the first statement.
I had such statement in my middleware, you can guess where that ended me up with. ;)
Mixing form fields, widgets and models.
Because the model can provide a "formfield", you start importing forms. It has a widget. That widget has some constants from .. er... the model. And now you have a loop. Better import that form field class inside the def formfield()
body instead of the global module scope.
A managers.py
that refers to constants of models.py
After all, the model needs the manager first. The manager can't start importing models.py
because it was still initializing. See below, because this is the most simple situation.
Using ugettext()
instead of ugettext_lazy
.
When you use ugettext()
, the translation system needs to initialize. It runs a scan over all packages in INSTALLED_APPS
, looking for a locale.XY.formats
package. When your app was just initializing itself, it now gets imported again by the global module scan.
Similar things happen with a scan for plugins, search_indexes by haystack, and other similar mechanisms.
Putting way too much in __init__.py
.
This is a combination of points 1 and 4, it stresses the import system because an import of a subpackage will first initialize all parent packages. In effect, a lot of code is running for a simple import and that increases the changes of having to import something from the wrong place.
The solution isn't that hard either. Once you have an idea of what is causing the loop, you remove that import statement out of the global imports (on top of the file) and place it inside a function that uses the symbol. For example:
# models.py:
from django.db import models
from mycms.managers import PageManager
class Page(models.Model)
PUBLISHED = 1
objects = PageManager()
# ....
# managers.py:
from django.db import models
class PageManager(models.Manager):
def published(self):
from mycms.models import Page # Import here to prevent circular imports
return self.filter(status=Page.PUBLISHED)
In this case, you can see models.py
really needs to import managers.py
; without it, it can't do the static initialisation of PageManager
. The other way around is not so critical. The Page
model could easily be imported inside a function instead of globally.
The same applies to any other situation of import errors. The loop may include a few more packages however.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…