mirror of https://github.com/django/django.git
Fixed #30351 -- Handled pre-existing permissions in proxy model permissions data migration.
Regression in 181fb60159
.
This commit is contained in:
parent
08a4ee0651
commit
98296f86b3
|
@ -1,5 +1,18 @@
|
|||
from django.db import migrations
|
||||
import sys
|
||||
|
||||
from django.core.management.color import color_style
|
||||
from django.db import migrations, transaction
|
||||
from django.db.models import Q
|
||||
from django.db.utils import IntegrityError
|
||||
|
||||
WARNING = """
|
||||
A problem arose migrating proxy model permissions for {old} to {new}.
|
||||
|
||||
Permission(s) for {new} already existed.
|
||||
Codenames Q: {query}
|
||||
|
||||
Ensure to audit ALL permissions for {old} and {new}.
|
||||
"""
|
||||
|
||||
|
||||
def update_proxy_model_permissions(apps, schema_editor, reverse=False):
|
||||
|
@ -7,6 +20,7 @@ def update_proxy_model_permissions(apps, schema_editor, reverse=False):
|
|||
Update the content_type of proxy model permissions to use the ContentType
|
||||
of the proxy model.
|
||||
"""
|
||||
style = color_style()
|
||||
Permission = apps.get_model('auth', 'Permission')
|
||||
ContentType = apps.get_model('contenttypes', 'ContentType')
|
||||
for Model in apps.get_models():
|
||||
|
@ -24,10 +38,16 @@ def update_proxy_model_permissions(apps, schema_editor, reverse=False):
|
|||
proxy_content_type = ContentType.objects.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
|
||||
Permission.objects.filter(
|
||||
permissions_query,
|
||||
content_type=old_content_type,
|
||||
).update(content_type=new_content_type)
|
||||
try:
|
||||
with transaction.atomic():
|
||||
Permission.objects.filter(
|
||||
permissions_query,
|
||||
content_type=old_content_type,
|
||||
).update(content_type=new_content_type)
|
||||
except IntegrityError:
|
||||
old = '{}_{}'.format(old_content_type.app_label, old_content_type.model)
|
||||
new = '{}_{}'.format(new_content_type.app_label, new_content_type.model)
|
||||
sys.stdout.write(style.WARNING(WARNING.format(old=old, new=new, query=permissions_query)))
|
||||
|
||||
|
||||
def revert_proxy_model_permissions(apps, schema_editor):
|
||||
|
|
|
@ -59,3 +59,8 @@ Bugfixes
|
|||
* Increased the default timeout when using ``Watchman`` to 5 seconds to prevent
|
||||
falling back to ``StatReloader`` on larger projects and made it customizable
|
||||
via the ``DJANGO_WATCHMAN_TIMEOUT`` environment variable (:ticket:`30361`).
|
||||
|
||||
* Fixed a regression in Django 2.2 that caused a crash when migrating
|
||||
permissions for proxy models if the target permissions already existed. For
|
||||
example, when a permission had been created manually or a model had been
|
||||
migrated from concrete to proxy (:ticket:`30351`).
|
||||
|
|
|
@ -4,6 +4,7 @@ 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.test.utils import captured_stdout
|
||||
|
||||
from .models import Proxy, UserProxy
|
||||
|
||||
|
@ -152,3 +153,27 @@ class ProxyModelWithSameAppLabelTests(TestCase):
|
|||
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_with_existing_target_permission(self):
|
||||
"""
|
||||
Permissions may already exist:
|
||||
|
||||
- Old workaround was to manually create permissions for proxy models.
|
||||
- Model may have been concrete and then converted to proxy.
|
||||
|
||||
Output a reminder to audit relevant permissions.
|
||||
"""
|
||||
proxy_model_content_type = ContentType.objects.get_for_model(Proxy, for_concrete_model=False)
|
||||
Permission.objects.create(
|
||||
content_type=proxy_model_content_type,
|
||||
codename='add_proxy',
|
||||
name='Can add proxy',
|
||||
)
|
||||
Permission.objects.create(
|
||||
content_type=proxy_model_content_type,
|
||||
codename='display_proxys',
|
||||
name='May display proxys information',
|
||||
)
|
||||
with captured_stdout() as stdout:
|
||||
update_proxy_permissions.update_proxy_model_permissions(apps, None)
|
||||
self.assertIn('A problem arose migrating proxy model permissions', stdout.getvalue())
|
||||
|
|
Loading…
Reference in New Issue