mirror of https://github.com/django/django.git
[3.0.x] Fixed #31021 -- Fixed proxy model permissions data migration crash with a multiple databases setup.
Regression in98296f86b3
. Backport ofe8fcdaad5c
from master
This commit is contained in:
parent
81ddf4b164
commit
ca9144a4a8
|
@ -23,6 +23,7 @@ def update_proxy_model_permissions(apps, schema_editor, reverse=False):
|
|||
style = color_style()
|
||||
Permission = apps.get_model('auth', 'Permission')
|
||||
ContentType = apps.get_model('contenttypes', 'ContentType')
|
||||
alias = schema_editor.connection.alias
|
||||
for Model in apps.get_models():
|
||||
opts = Model._meta
|
||||
if not opts.proxy:
|
||||
|
@ -34,13 +35,14 @@ def update_proxy_model_permissions(apps, schema_editor, reverse=False):
|
|||
permissions_query = Q(codename__in=proxy_default_permissions_codenames)
|
||||
for codename, name in opts.permissions:
|
||||
permissions_query = permissions_query | Q(codename=codename, name=name)
|
||||
concrete_content_type = ContentType.objects.get_for_model(Model, for_concrete_model=True)
|
||||
proxy_content_type = ContentType.objects.get_for_model(Model, for_concrete_model=False)
|
||||
content_type_manager = ContentType.objects.db_manager(alias)
|
||||
concrete_content_type = content_type_manager.get_for_model(Model, for_concrete_model=True)
|
||||
proxy_content_type = content_type_manager.get_for_model(Model, for_concrete_model=False)
|
||||
old_content_type = proxy_content_type if reverse else concrete_content_type
|
||||
new_content_type = concrete_content_type if reverse else proxy_content_type
|
||||
try:
|
||||
with transaction.atomic():
|
||||
Permission.objects.filter(
|
||||
with transaction.atomic(using=alias):
|
||||
Permission.objects.using(alias).filter(
|
||||
permissions_query,
|
||||
content_type=old_content_type,
|
||||
).update(content_type=new_content_type)
|
||||
|
|
|
@ -13,3 +13,7 @@ Bugfixes
|
|||
* Fixed a data loss possibility in the admin changelist view when a custom
|
||||
:ref:`formset's prefix <formset-prefix>` contains regular expression special
|
||||
characters, e.g. `'$'` (:ticket:`31031`).
|
||||
|
||||
* Fixed a regression in Django 2.2.1 that caused a crash when migrating
|
||||
permissions for proxy models with a multiple database setup if the
|
||||
``default`` entry was empty (:ticket:`31021`).
|
||||
|
|
|
@ -3,7 +3,8 @@ from importlib import import_module
|
|||
from django.apps import apps
|
||||
from django.contrib.auth.models import Permission, User
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.test import TestCase
|
||||
from django.db import connection, connections
|
||||
from django.test import TransactionTestCase
|
||||
from django.test.utils import captured_stdout
|
||||
|
||||
from .models import Proxy, UserProxy
|
||||
|
@ -11,7 +12,7 @@ from .models import Proxy, UserProxy
|
|||
update_proxy_permissions = import_module('django.contrib.auth.migrations.0011_update_proxy_permissions')
|
||||
|
||||
|
||||
class ProxyModelWithDifferentAppLabelTests(TestCase):
|
||||
class ProxyModelWithDifferentAppLabelTests(TransactionTestCase):
|
||||
available_apps = [
|
||||
'auth_tests',
|
||||
'django.contrib.auth',
|
||||
|
@ -41,7 +42,8 @@ class ProxyModelWithDifferentAppLabelTests(TestCase):
|
|||
proxy_model_content_type = ContentType.objects.get_for_model(UserProxy, for_concrete_model=False)
|
||||
self.assertEqual(self.default_permission.content_type, self.concrete_content_type)
|
||||
self.assertEqual(self.custom_permission.content_type, self.concrete_content_type)
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, None)
|
||||
with connection.schema_editor() as editor:
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, editor)
|
||||
self.default_permission.refresh_from_db()
|
||||
self.assertEqual(self.default_permission.content_type, proxy_model_content_type)
|
||||
self.custom_permission.refresh_from_db()
|
||||
|
@ -54,7 +56,8 @@ class ProxyModelWithDifferentAppLabelTests(TestCase):
|
|||
for permission in [self.default_permission, self.custom_permission]:
|
||||
self.assertTrue(user.has_perm('auth.' + permission.codename))
|
||||
self.assertFalse(user.has_perm('auth_tests.' + permission.codename))
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, None)
|
||||
with connection.schema_editor() as editor:
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, editor)
|
||||
# Reload user to purge the _perm_cache.
|
||||
user = User._default_manager.get(pk=user.pk)
|
||||
for permission in [self.default_permission, self.custom_permission]:
|
||||
|
@ -62,8 +65,9 @@ class ProxyModelWithDifferentAppLabelTests(TestCase):
|
|||
self.assertTrue(user.has_perm('auth_tests.' + permission.codename))
|
||||
|
||||
def test_migrate_backwards(self):
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, None)
|
||||
update_proxy_permissions.revert_proxy_model_permissions(apps, None)
|
||||
with connection.schema_editor() as editor:
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, editor)
|
||||
update_proxy_permissions.revert_proxy_model_permissions(apps, editor)
|
||||
self.default_permission.refresh_from_db()
|
||||
self.assertEqual(self.default_permission.content_type, self.concrete_content_type)
|
||||
self.custom_permission.refresh_from_db()
|
||||
|
@ -76,8 +80,9 @@ class ProxyModelWithDifferentAppLabelTests(TestCase):
|
|||
for permission in [self.default_permission, self.custom_permission]:
|
||||
self.assertTrue(user.has_perm('auth.' + permission.codename))
|
||||
self.assertFalse(user.has_perm('auth_tests.' + permission.codename))
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, None)
|
||||
update_proxy_permissions.revert_proxy_model_permissions(apps, None)
|
||||
with connection.schema_editor() as editor:
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, editor)
|
||||
update_proxy_permissions.revert_proxy_model_permissions(apps, editor)
|
||||
# Reload user to purge the _perm_cache.
|
||||
user = User._default_manager.get(pk=user.pk)
|
||||
for permission in [self.default_permission, self.custom_permission]:
|
||||
|
@ -85,7 +90,7 @@ class ProxyModelWithDifferentAppLabelTests(TestCase):
|
|||
self.assertFalse(user.has_perm('auth_tests.' + permission.codename))
|
||||
|
||||
|
||||
class ProxyModelWithSameAppLabelTests(TestCase):
|
||||
class ProxyModelWithSameAppLabelTests(TransactionTestCase):
|
||||
available_apps = [
|
||||
'auth_tests',
|
||||
'django.contrib.auth',
|
||||
|
@ -115,7 +120,8 @@ class ProxyModelWithSameAppLabelTests(TestCase):
|
|||
proxy_model_content_type = ContentType.objects.get_for_model(Proxy, for_concrete_model=False)
|
||||
self.assertEqual(self.default_permission.content_type, self.concrete_content_type)
|
||||
self.assertEqual(self.custom_permission.content_type, self.concrete_content_type)
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, None)
|
||||
with connection.schema_editor() as editor:
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, editor)
|
||||
self.default_permission.refresh_from_db()
|
||||
self.custom_permission.refresh_from_db()
|
||||
self.assertEqual(self.default_permission.content_type, proxy_model_content_type)
|
||||
|
@ -127,15 +133,17 @@ class ProxyModelWithSameAppLabelTests(TestCase):
|
|||
user.user_permissions.add(self.custom_permission)
|
||||
for permission in [self.default_permission, self.custom_permission]:
|
||||
self.assertTrue(user.has_perm('auth_tests.' + permission.codename))
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, None)
|
||||
with connection.schema_editor() as editor:
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, editor)
|
||||
# Reload user to purge the _perm_cache.
|
||||
user = User._default_manager.get(pk=user.pk)
|
||||
for permission in [self.default_permission, self.custom_permission]:
|
||||
self.assertTrue(user.has_perm('auth_tests.' + permission.codename))
|
||||
|
||||
def test_migrate_backwards(self):
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, None)
|
||||
update_proxy_permissions.revert_proxy_model_permissions(apps, None)
|
||||
with connection.schema_editor() as editor:
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, editor)
|
||||
update_proxy_permissions.revert_proxy_model_permissions(apps, editor)
|
||||
self.default_permission.refresh_from_db()
|
||||
self.assertEqual(self.default_permission.content_type, self.concrete_content_type)
|
||||
self.custom_permission.refresh_from_db()
|
||||
|
@ -147,8 +155,9 @@ class ProxyModelWithSameAppLabelTests(TestCase):
|
|||
user.user_permissions.add(self.custom_permission)
|
||||
for permission in [self.default_permission, self.custom_permission]:
|
||||
self.assertTrue(user.has_perm('auth_tests.' + permission.codename))
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, None)
|
||||
update_proxy_permissions.revert_proxy_model_permissions(apps, None)
|
||||
with connection.schema_editor() as editor:
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, editor)
|
||||
update_proxy_permissions.revert_proxy_model_permissions(apps, editor)
|
||||
# Reload user to purge the _perm_cache.
|
||||
user = User._default_manager.get(pk=user.pk)
|
||||
for permission in [self.default_permission, self.custom_permission]:
|
||||
|
@ -175,5 +184,36 @@ class ProxyModelWithSameAppLabelTests(TestCase):
|
|||
name='May display proxys information',
|
||||
)
|
||||
with captured_stdout() as stdout:
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, None)
|
||||
with connection.schema_editor() as editor:
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, editor)
|
||||
self.assertIn('A problem arose migrating proxy model permissions', stdout.getvalue())
|
||||
|
||||
|
||||
class MultiDBProxyModelAppLabelTests(TransactionTestCase):
|
||||
databases = {'default', 'other'}
|
||||
available_apps = [
|
||||
'auth_tests',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
ContentType.objects.all().delete()
|
||||
Permission.objects.using('other').delete()
|
||||
concrete_content_type = ContentType.objects.db_manager(
|
||||
'other'
|
||||
).get_for_model(Proxy)
|
||||
self.permission = Permission.objects.using('other').create(
|
||||
content_type=concrete_content_type,
|
||||
codename='add_proxy',
|
||||
name='Can add proxy',
|
||||
)
|
||||
|
||||
def test_migrate_other_database(self):
|
||||
proxy_model_content_type = ContentType.objects.db_manager(
|
||||
'other'
|
||||
).get_for_model(Proxy, for_concrete_model=False)
|
||||
with connections['other'].schema_editor() as editor:
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, editor)
|
||||
self.permission.refresh_from_db()
|
||||
self.assertEqual(self.permission.content_type, proxy_model_content_type)
|
||||
|
|
Loading…
Reference in New Issue