Opened 13 years ago

Closed 13 years ago

Last modified 13 years ago

#16283 closed Bug (fixed)

manage.py depends on django.contrib.contenttypes et al.

Reported by: TheRoSS Owned by: nobody
Component: contrib.auth Version: 1.3
Severity: Normal Keywords:
Cc: TheRoSS Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I intended to use django.contrib.auth with my own backends, so I included 'django.contrib.auth.middleware.AuthenticationMiddleware' into 'MIDDLEWARE_CLASSES', excluded 'django.contrib.auth' from 'INSTALLED_APPS' and created my own authentication application.

But if I named my authentication application as 'project.auth', django used models from 'django.contrib.auth'.
If I gave it any other name, 'project.auth2' for example, models were mine.

project.settings contains:

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
)

INSTALLED_APPS = (
    'project.auth',    # DOESN'T WORK!
    'project.auth2',   # works well
)

I tracked down the source code and realized that django.db.models.loading.app_models dictionary has a record named 'auth' taken from 'django.contrib.auth' (upon middleware processing I suppose) which prevents my 'auth' application to be used.

Attachments (1)

seka.zip (1.9 KB ) - added by TheRoSS 13 years ago.

Download all attachments as: .zip

Change History (12)

comment:1 by TheRoSS, 13 years ago

Cc: TheRoSS added

comment:2 by Aymeric Augustin, 13 years ago

Resolution: invalid
Status: newclosed

This works as advertised: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps

It's very hard to remove this limitation in a backwards compatible way because Django references models in many places as <app_module>.<ModelClass>, which gets translated to <path>.<to>.<app_module>.models.<ModelClass>.

comment:3 by TheRoSS, 13 years ago

Resolution: invalid
Status: closedreopened

No! The problem is that I didn't used 'django.contrib.auth' at all! But cannot name my application 'auth'.

My settings.py file:

DEBUG = True
TEMPLATE_DEBUG = DEBUG

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'seka',                      # Or path to database file if using sqlite3.
        'USER': 'root',                      # Not used with sqlite3.
        'PASSWORD': 'root',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
)

ROOT_URLCONF = 'seka.urls'

INSTALLED_APPS = (
    'seka.auth',
)

My models.py:

from django.db import models
from django.utils.translation import ugettext_lazy as _

# Create your models here.
class User (models.Model):
    username = models.CharField(_('username'), max_length=30, unique=True, help_text=_("Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"))

Bu running 'manage.py sql auth' gives:

BEGIN;
CREATE TABLE `auth_permission` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `name` varchar(50) NOT NULL,
    `content_type_id` integer NOT NULL,
    `codename` varchar(100) NOT NULL,
    UNIQUE (`content_type_id`, `codename`)
)
;
CREATE TABLE `auth_group_permissions` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `group_id` integer NOT NULL,
    `permission_id` integer NOT NULL,
    UNIQUE (`group_id`, `permission_id`)
)
;
ALTER TABLE `auth_group_permissions` ADD CONSTRAINT `permission_id_refs_id_5886d21f` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`);
CREATE TABLE `auth_group` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `name` varchar(80) NOT NULL UNIQUE
)
;
ALTER TABLE `auth_group_permissions` ADD CONSTRAINT `group_id_refs_id_3cea63fe` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`);
CREATE TABLE `auth_user_user_permissions` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `user_id` integer NOT NULL,
    `permission_id` integer NOT NULL,
    UNIQUE (`user_id`, `permission_id`)
)
;
ALTER TABLE `auth_user_user_permissions` ADD CONSTRAINT `permission_id_refs_id_67e79cb` FOREIGN KEY (`permission_id`) REFERENCES `auth_permission` (`id`);
CREATE TABLE `auth_user_groups` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `user_id` integer NOT NULL,
    `group_id` integer NOT NULL,
    UNIQUE (`user_id`, `group_id`)
)
;
ALTER TABLE `auth_user_groups` ADD CONSTRAINT `group_id_refs_id_f116770` FOREIGN KEY (`group_id`) REFERENCES `auth_group` (`id`);
CREATE TABLE `auth_user` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `username` varchar(30) NOT NULL UNIQUE,
    `first_name` varchar(30) NOT NULL,
    `last_name` varchar(30) NOT NULL,
    `email` varchar(75) NOT NULL,
    `password` varchar(128) NOT NULL,
    `is_staff` bool NOT NULL,
    `is_active` bool NOT NULL,
    `is_superuser` bool NOT NULL,
    `last_login` datetime NOT NULL,
    `date_joined` datetime NOT NULL
)
;
ALTER TABLE `auth_user_user_permissions` ADD CONSTRAINT `user_id_refs_id_dfbab7d` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`);
ALTER TABLE `auth_user_groups` ADD CONSTRAINT `user_id_refs_id_7ceef80f` FOREIGN KEY (`user_id`) REFERENCES `auth_user`(`id`);
CREATE TABLE `auth_message` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `user_id` integer NOT NULL,
    `message` longtext NOT NULL
)
;
ALTER TABLE `auth_message` ADD CONSTRAINT `user_id_refs_id_650f49a6` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`);
-- The following references should be added but depend on non-existent tables:
-- ALTER TABLE `auth_permission` ADD CONSTRAINT `content_type_id_refs_id_728de91f` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`);
COMMIT;

comment:4 by Aymeric Augustin, 13 years ago

Resolution: invalid
Status: reopenedclosed

tl;dr don't call your app "auth" :)


You have django.contrib.auth.middleware.AuthenticationMiddleware in MIDDLEWARE_CLASSES.

By default, this will use django.contrib.auth.backends.ModelBackend as an authentication backend (https://docs.djangoproject.com/en/dev/ref/settings/#authentication-backends).

This backend imports django.contrib.auth.models (https://code.djangoproject.com/browser/django/trunk/django/contrib/auth/backends.py)

Thus, even if you haven't declared django.contrib.auth in INSTALLED_APPS, it gets registered in the application cache, creating a conflict with your app.

I hope this helps!

comment:5 by TheRoSS, 13 years ago

Resolution: invalid
Status: closedreopened

I think there is a misunderstanding between us...
I didn't used 'django.contrib.auth' at all, look at my second post, please.
There is no 'django.contrib.auth.middleware.AuthenticationMiddleware' in MIDDLEWARE_CLASSES

I raised an exeption at the beginning of 'django.contrib.auth.models'. Look at the exception stack, please:

Traceback (most recent call last):
  File "C:\home\dev\seka\seka\manage.py", line 14, in <module>
    execute_manager(settings)
  File "C:\home\python\lib\site-packages\django\core\management\__init__.py", line 438, in execute_manager
    utility.execute()
  File "C:\home\python\lib\site-packages\django\core\management\__init__.py", line 379, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\home\python\lib\site-packages\django\core\management\base.py", line 191, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "C:\home\python\lib\site-packages\django\core\management\base.py", line 219, in execute
    self.validate()
  File "C:\home\python\lib\site-packages\django\core\management\base.py", line 243, in validate
    from django.core.management.validation import get_validation_errors
  File "C:\home\python\lib\site-packages\django\core\management\validation.py", line 3, in <module>
    from django.contrib.contenttypes.generic import GenericForeignKey, GenericRelation
  File "C:\home\python\lib\site-packages\django\contrib\contenttypes\generic.py", line 13, in <module>
    from django.contrib.admin.options import InlineModelAdmin, flatten_fieldsets
  File "C:\home\python\lib\site-packages\django\contrib\admin\__init__.py", line 6, in <module>
    from django.contrib.admin.sites import AdminSite, site
  File "C:\home\python\lib\site-packages\django\contrib\admin\sites.py", line 4, in <module>
    from django.contrib.admin.forms import AdminAuthenticationForm
  File "C:\home\python\lib\site-packages\django\contrib\admin\forms.py", line 4, in <module>
    from django.contrib.auth.forms import AuthenticationForm
  File "C:\home\python\lib\site-packages\django\contrib\auth\forms.py", line 1, in <module>
    from django.contrib.auth.models import User
  File "C:\home\python\lib\site-packages\django\contrib\auth\models.py", line 15, in <module>
    raise 'AUTH MODELS CALLED'

So 'auth' package was called from 'admin' package which was called from 'contenttypes' which was called from django core.

I didn't included those packages in my settings, but they were called anymore.
Is this ok?
Are the names 'auth', 'admin', 'contenttypes' magic and forbidden to use as an application names?

I attach my zipped example project with this message, hope it will be helpful.

by TheRoSS, 13 years ago

Attachment: seka.zip added

comment:6 by Aymeric Augustin, 13 years ago

Summary: my application project.auth takes models from django.contrib.authmanage.py depends on django.contrib.contenttypes et al.
Triage Stage: UnreviewedAccepted

Your original report contained django.contrib.auth.middleware.AuthenticationMiddleware, and I missed the fact that the example you posted later on didn't — sorry about that.

Thanks for your example. It really helped me reproduce the problem quickly. Indeed, I obtain this:

% ./manage.py sql --traceback all
Error: One or more models did not validate:
auth.permission: 'content_type' has a relation with model <class 'django.contrib.contenttypes.models.ContentType'>, which has either not been installed or is abstract.

And by raising an exception in django.contrib.auth.models, I reproduce your backtrace. It shows that manage.py depends on contenttypes, admin and auth, which is bad because django's core is supposed not to depend on contrib apps.

The root cause of the problem is the fact that since r14563 django.core.management.validation depends on django.contrib.contenttypes. I am going to update the summary to reflect this.

comment:7 by Ramiro Morales, 13 years ago

Seems like in the short term we'd need to undo the changes from [14563]. Long term solution for validate core management command extensibility is what #8579 asks for.

comment:8 by Jannis Leidel, 13 years ago

I could see the validate command calling a specific hook in the app classes (e.g. a validate method) once the app-loading branch lands.

comment:9 by Ramiro Morales, 13 years ago

Resolution: fixed
Status: reopenedclosed

In [16493]:

(The changeset message doesn't reference this ticket)

comment:11 by Ramiro Morales, 13 years ago

In [16541]:

[1.3.X] Reverted [14563] because it introduced a dependency from core on a contrib app (contenttypes). Fixes #16283, Refs #3055. Thanks TheRoSS for the report and Aymeric Augustin for finding the problem.

This caused models shipped with some contrib apps to pollute the namespace when user's apps had the same name (e.g. auth, sites), even when these contrib apps weren't installed.

This undesired loading of contrib apps happened when model validation was executed, for example when running management commands that set or inherit requires_model_validation=True:
cleanup, dumpdata, flush, loaddata, reset, runfcgi, sql, sqlall, sqlclear, sqlcustom, sqlflush, sqlindexes, sqlinitialdata, sqlreset, sqlsequencereset, syncdb, createsuperusers, ping_google, collectstatic, findstatic.

This could also cause hard to diagnose problems e.g. when performing reverse URL resolving.

Backport of [16493] from trunk.

comment:12 by Aymeric Augustin, 13 years ago

#16755 was a duplicate.

Note: See TracTickets for help on using tickets.
Back to Top