joanbm joanbm - 3 months ago 15
Python Question

Package's namespace polluted by Django?

Django 1.8

For no obvious reasons, global variable defined in package's module is replaced between its initial assignment and deferred function call.

Minimal Django project is created with

django-admin startproject
. New empty application added with
django-admin startapp simplelib
. New app
added to
of project's

Bellow is the only added code:

# content of
from django.db import models
from django.db.models.signals import class_prepared

def myhandler(sender, **kwargs):
print 'models from myhandler: {}'.format(models)

def direct_call():
print 'models from direct_call: {}'.format(models)


print 'models from top namespace: {}'.format(models)


When project is run with runserver
, following output is produced:

models from top namespace: <module 'django.db.models' from '/home/<snip>/Projects/Python/django-projects/lib/python2.7/site-packages/django/db/models/__init__.pyc'>
models from direct_all: <module 'django.db.models' from '/home/<snip>/Projects/Python/django-projects/lib/python2.7/site-packages/django/db/models/__init__.pyc'>
models from myhandler: <module 'simplelib.models' from '/home/<snip>/Projects/Python/django-projects/myproject/simplelib/models.pyc'>

See, when signal handler function is invoked,
global variable is changed.
There is no other project's code. It has to be altered by Django itself.

Note: above described effect applies only when
is placed at the start of
tuple. When added at the end,
still points to
, as expected.

Any idea what's going here ?


This is normal Python behaviour.

When you import a submodule, that submodule is set as an attribute on the parent module. In this case, when simplelib.models is imported, the models submodule is set on the parent module simplelib. The parent module namespace is the same as that module's global namespace. This will overwrite the old value.

If you put simplelib as the first entry in INSTALLED_APPS, its models submodule will be the first models module imported by Django. This will replace the simplelib.models attribute before any model fires the class_prepared signal. On the other hand, if you put simplelib at the end of INSTALLED_APPS, Django will load simpellib.models as the last models module. Any models that are imported before that will fire the class_prepared signal before simplelib.models is imported, and before the models attribute is replaced with the submodule.