Code

Opened 16 months ago

Closed 16 months ago

Last modified 16 months ago

#19472 closed Bug (fixed)

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

Reported by: gcc 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?

Attachments (0)

Change History (3)

comment:1 Changed 16 months ago by russellm

  • Component changed from contrib.auth to Documentation
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Severity changed from Normal to Release blocker
  • Triage Stage changed from Unreviewed to Accepted
  • Type changed from Uncategorized to Bug

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 Changed 16 months ago by Russell Keith-Magee <russell@…>

  • Resolution set to fixed
  • Status changed from new to closed

In bd414aed01d48339ed02b9714565939536ffbfcb:

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

Thanks to gcc for the report.

comment:3 Changed 16 months ago by Russell Keith-Magee <russell@…>

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.

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.