1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 |
- 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):
- """
- 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():
- opts = Model._meta
- if not opts.proxy:
- continue
- proxy_default_permissions_codenames = [
- '%s_%s' % (action, opts.model_name)
- for action in opts.default_permissions
- ]
- 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)
- 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(
- 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):
- """
- Update the content_type of proxy model permissions to use the ContentType
- of the concrete model.
- """
- update_proxy_model_permissions(apps, schema_editor, reverse=True)
-
-
- class Migration(migrations.Migration):
- dependencies = [
- ('auth', '0010_alter_group_name_max_length'),
- ('contenttypes', '0002_remove_content_type_name'),
- ]
- operations = [
- migrations.RunPython(update_proxy_model_permissions, revert_proxy_model_permissions),
- ]
|