Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python import problem with Django management commands

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?

like image 550
Brian Neal Avatar asked Sep 14 '10 18:09

Brian Neal


People also ask

How do you pass arguments in Django management command?

The parameter parser is an instance of argparse. ArgumentParser (see the docs). Now you can add as many arguments as you want by calling parser 's add_argument method. In the code above, you are expecting a parameter n of type int which is gotten in the handle method from options .

What is Django admin command?

django-admin is Django's command-line utility for administrative tasks. This document outlines all it can do. In addition, manage.py is automatically created in each Django project.

What is the work of manage py in Django?

It is your tool for executing many Django-specific tasks -- starting a new app within a project, running the development server, running your tests... It is also an extension point where you can access custom commands you write yourself that are specific to your apps.


1 Answers

If some random module ever imports module x.y.z, then a later person who imports just x.y will see a z in the x.y namespace.

The reason this happens is that import x.y.z is actually three import statements in one. It works something like this:

x = __internal_import('x')
x.y = __internal_import('x/y')
x.y.z = __internal_import('x/y/z')

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 its z member assigned to the z 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.)

like image 175
apenwarr Avatar answered Sep 25 '22 03:09

apenwarr