Opened 8 months ago

Closed 7 months ago

#22956 closed Bug (fixed)

PermissionManager.get_by_natural_key doesn't fetch ContentType from same DB

Reported by: jyrno@… Owned by: nobody
Component: contrib.auth Version: 1.6
Severity: Normal Keywords: auth contenttype natural_keys user permissions natural keys multiple databases
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Currently, when an user has multiple databases configured, and dumps
his auth.* tables using dumpdata command with --natural flag.

Then loads the dump to the other (non-default) database
there seems to be an issue with selecting the correct
content type for the permission from the specified database.

E.g. The PermissionManager gets the id in get_by_natural_key
from the default database while --database=other was explicitly
specified.

Note: This will all be ok, if both tables have been synced with the same
INSTALLED_APP setting. (since both databases have the same real ids,
for content_type models.)

Issue was reproduced on both django 1.5.5 and django 1.6.

How to reproduce
I have attached an example app to the bug report that does the same.

1. Have two empty databases in the settings
2. Create a another settings file, which extends 
   the default settings but shuffles the installed apps
3. Run the following commands

$ python manage.py syncdb --database=default --noinput
 
# Settings.other has installed apps in a different order.
$ python manage.py syncdb --database=other --noinput --settings=settings.other
 
# Create a problematic user: (python manage.py shell --database=default)
from django.contrib.auth.models import User, Permission
user, created = User.objects.get_or_create(username='test_usr', is_staff=True, password='abcd')
for permission in Permission.objects.all():
    user.user_permissions.add(permission)
 
# Dump data from the original database
python manage.py dumpdata auth.User --indent=2 --database=default --natural > users.json
 
# Load it to the other database
python manage.py loaddata --database=other --trace users.json

# Results in "Permission matching query does not exist" since 
the contenttype id is from the default.

MonkeyPatch:

from django.contrib.auth import models as auth_models
from django.contrib.contenttypes.models import ContentType

def patched_get_by_natural_key(self, codename, app_label, model):
    return self.get(
        codename=codename,
        content_type=ContentType.objects.db_manager(self.db).get_by_natural_key(app_label, model),
    )
auth_models.PermissionManager.get_by_natural_key = patched_get_by_natural_key

Attachments (1)

testCase.tar.gz (5.8 KB) - added by jyrno@… 8 months ago.
Example app reproducing the issue

Download all attachments as: .zip

Change History (7)

Changed 8 months ago by jyrno@…

Example app reproducing the issue

comment:1 Changed 8 months ago by timo

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Summary changed from loaddata user_permissions from db A to B with natural keys to PermissionManager.get_by_natural_key doesn't fetch ContentType from same DB
  • Triage Stage changed from Unreviewed to Accepted

Fix looks reasonable. Can you add a test?

comment:3 Changed 8 months ago by timo

  • Has patch set
  • Patch needs improvement set

Please uncheck "Patch needs improvement" if you can update the PR per my comments; thanks!

comment:4 Changed 8 months ago by anonymous

  • Patch needs improvement unset

Will update the pull request next week.

comment:5 Changed 7 months ago by jyrno@…

comment:6 Changed 7 months ago by Tim Graham <timograham@…>

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

In 76f2f58a1853fd7a774f3df3fe454022a0206ff9:

Fixed #22956 -- Made PermissionManager.get_by_natural_key() use the correct database for content type lookup.

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