For whatever reason, when I was new to Python and Django, I wrote some import statements like this at the top of a models.py file:
from django.contrib import auth
And I'd use it like this:
class MyModel(models.Model):
user = models.ForeignKey(auth.models.User)
# ...
This worked fine. A long time later, I wrote a custom management command, and it would do this:
from myapp.models import MyModel
When I ran my custom command (python manage.py my_command
) this would result in Python complaining that the module auth
had no attribute models
on the line declaring the ForeignKey
in models.py.
To work around this problem, I changed my models.py to the more usual:
from django.contrib.auth.models import User
class MyModel(models.Model):
user = models.ForeignKey(User)
# ...
Can someone explain to me what I am missing? Is there something different in the environment when you run a management command? Or was I just doing it wrong the whole time? Thanks!
Edit: Following dmitko's hunch about circular imports, here are the imports used in my models.py file. I'm showing the original import of auth
commented out, along with the only model that has a foreign key to the auth user model:
import datetime
from django.db import models
# from django.contrib import auth
from django.contrib.auth.models import User
class UserLastVisit(models.Model):
# user = models.ForeignKey(auth.models.User, unique=True)
# ^^^^^^^^^^^^^^^^
# after adding mgmt command, error occurred here; change to the line below
user = models.ForeignKey(User, unique=True)
last_visit = models.DateTimeField(db_index=True)
And here are the imports of the management command that uncovered the problem:
import datetime
from django.core.management.base import NoArgsCommand
from core.models import UserLastVisit, AnonLastVisit, Statistic
Was this setting up a circular import type situation?
It's hard to say exactly what's going on without seeing the new manage.py command that you added. However, I often see the " has no attribute " in cases with circular imports, and it's almost always fixed by changing the module-level imports to function- or class-level imports, as you did here. You might check if anything like that is going on here.
I guess that if you do
from django.contrib import auth
that means you're importing auth package as a module and what it exports is driven by__init__.py
in the auth folder:You can check
__init__.py
indjango\contrib\auth
and see the same function list. When you importfrom django.contrib.auth.models import User
that means that you're importing a submodule from theauth
package and it works.BTW. I was unable to use
auth.models.User
in any case - whether I run from console or from my django app.If some random module ever imports module
x.y.z
, then a later person who imports justx.y
will see az
in thex.y
namespace.The reason this happens is that
import x.y.z
is actually three import statements in one. It works something like this:Next time someone does
__internal_import('x/y')
, they'll get the same object, because python is smart enough not to import the same one twice. That object already has itsz
member assigned to thez
module.In your full app, probably you had a module that did
import django.contrib.auth.models
. But your minimal standalone program didn't import that module, so the name was never assigned.(Note: there's no such thing as
__internal_import
. It's just an illustration. The real function has some other name that you would have to look up.)