Opened 12 years ago

Closed 12 years ago

Last modified 12 years ago

#19472 closed Bug (fixed)

AttributeError: Problem installing auth.user fixtures with swapped user model

Reported by: Chris Wilson Owned by: nobody
Component: Documentation Version: 1.5-beta-1
Severity: Release blocker Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

If a project swaps out a user model, then fixtures in apps that refer to
auth.user don't work, which breaks their tests. This makes it impossible
to write reusable apps whose tests still work when the user model is
swapped out.

I've created a test case which fails like this:

chris@lap-x201:~/user_swapout_test/project$ ../ve/bin/python manage.py test app_with_user_fixtures
Creating test database for alias 'default'...
E
======================================================================
ERROR: test_basic_addition (app_with_user_fixtures.tests.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/installuser/Dropbox/projects/ischool/user_swapout_test/ve/local/lib/python2.7/site-packages/django/test/testcases.py", line 256, in __call__
    self._pre_setup()
  File "/home/installuser/Dropbox/projects/ischool/user_swapout_test/ve/local/lib/python2.7/site-packages/django/test/testcases.py", line 450, in _pre_setup
    self._fixture_setup()
  File "/home/installuser/Dropbox/projects/ischool/user_swapout_test/ve/local/lib/python2.7/site-packages/django/test/testcases.py", line 828, in _fixture_setup
    'skip_validation': True,
  File "/home/installuser/Dropbox/projects/ischool/user_swapout_test/ve/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 161, in call_command
    return klass.execute(*args, **defaults)
  File "/home/installuser/Dropbox/projects/ischool/user_swapout_test/ve/local/lib/python2.7/site-packages/django/core/management/base.py", line 252, in execute
    output = self.handle(*args, **options)
  File "/home/installuser/Dropbox/projects/ischool/user_swapout_test/ve/local/lib/python2.7/site-packages/django/core/management/commands/loaddata.py", line 111, in handle
    self.load_label(fixture_label, app_fixtures)
  File "/home/installuser/Dropbox/projects/ischool/user_swapout_test/ve/local/lib/python2.7/site-packages/django/core/management/commands/loaddata.py", line 194, in load_label
    formats)
  File "/home/installuser/Dropbox/projects/ischool/user_swapout_test/ve/local/lib/python2.7/site-packages/django/core/management/commands/loaddata.py", line 246, in process_dir
    obj.save(using=self.using)
  File "/home/installuser/Dropbox/projects/ischool/user_swapout_test/ve/local/lib/python2.7/site-packages/django/core/serializers/base.py", line 167, in save
    models.Model.save_base(self.object, using=using, raw=True)
  File "/home/installuser/Dropbox/projects/ischool/user_swapout_test/ve/local/lib/python2.7/site-packages/django/db/models/base.py", line 604, in save_base
    manager.using(using).filter(pk=pk_val).exists())):
AttributeError: Problem installing fixture '/home/installuser/Dropbox/projects/ischool/user_swapout_test/project/app_with_user_fixtures/fixtures/users.json': 'NoneType' object has no attribute 'using'

----------------------------------------------------------------------
Ran 0 tests in 0.006s

FAILED (errors=1)
Destroying test database for alias 'default'...

If I add some instrumentation to find out why the manager is None:

manager = cls._base_manager
if manager is None:
    raise ValueError(("%s must have a valid Manager to create " +
        "instances") % cls)

Then I can see that it's django.contrib.auth.models.User that has no manager:

ValueError: Problem installing fixture '/home/installuser/Dropbox/projects/ischool/user_swapout_test/project/app_with_user_fixtures/fixtures/users.json': <class 'django.contrib.auth.models.User'> must have a valid Manager to create instances

I wonder if we need a special case for UserModel in fixtures. Of course if you swap out the user model for one that doesn't contain the necessary fields, then the fixture cannot be loaded, and the test should fail in that case. But when the fields are present, we should be able to load the fixtures.

Perhaps we could special case the content_type auth.user and any (future) swappable model class content types, to refer to the swapped-in model instead of the swapped-out one, for backwards compatibility?

Change History (3)

comment:1 by Russell Keith-Magee, 12 years ago

Component: contrib.authDocumentation
Severity: NormalRelease blocker
Triage Stage: UnreviewedAccepted
Type: UncategorizedBug

Changing the reference to the User model won't work, because there's no guarantee that the User model in the fixture will be compatible with the user model that is in use. For example, if I change the USERNAME_FIELD, no fixture with a 'username' will load.

However, this is clearly a real problem -- and there's a fix in the existing codebase. Django's own auth system needs to be protected against this exact problem, so there's a skipIfCustomUser in django.contrib.auth.tests.utils. Documenting this decorator as a general utility is the only way I can see around this problem in the general case.

comment:2 by Russell Keith-Magee <russell@…>, 12 years ago

Resolution: fixed
Status: newclosed

In bd414aed01d48339ed02b9714565939536ffbfcb:

Fixed #19472 -- Documented the testing requirements and tools for custom User models.

Thanks to gcc for the report.

comment:3 by Russell Keith-Magee <russell@…>, 12 years ago

In a7465ee7dfe7ced5f057de1b75e4ec05de3e38e5:

[1.5.X] Fixed #19472 -- Documented the testing requirements and tools for custom User models.

Thanks to gcc for the report.

Backport of bd414aed01d48339ed02b9714565939536ffbfcb from master.

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