Opened 3 years ago

Closed 2 years 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


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

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 syncdb --database=default --noinput
# Settings.other has installed apps in a different order.
$ python syncdb --database=other --noinput --settings=settings.other
# Create a problematic user: (python 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():
# Dump data from the original database
python dumpdata auth.User --indent=2 --database=default --natural > users.json
# Load it to the other database
python loaddata --database=other --trace users.json

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


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(
        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@… 3 years ago.
Example app reproducing the issue

Download all attachments as: .zip

Change History (7)

Changed 3 years ago by jyrno@…

Attachment: testCase.tar.gz added

Example app reproducing the issue

comment:1 Changed 3 years ago by Tim Graham

Summary: loaddata user_permissions from db A to B with natural keysPermissionManager.get_by_natural_key doesn't fetch ContentType from same DB
Triage Stage: UnreviewedAccepted

Fix looks reasonable. Can you add a test?

comment:3 Changed 3 years ago by Tim Graham

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 3 years ago by anonymous

Patch needs improvement: unset

Will update the pull request next week.

comment:5 Changed 2 years ago by jyrno@…

comment:6 Changed 2 years ago by Tim Graham <timograham@…>

Resolution: fixed
Status: newclosed

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