You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

0011_update_proxy_permissions.py 2.6KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import sys
  2. from django.core.management.color import color_style
  3. from django.db import migrations, transaction
  4. from django.db.models import Q
  5. from django.db.utils import IntegrityError
  6. WARNING = """
  7. A problem arose migrating proxy model permissions for {old} to {new}.
  8. Permission(s) for {new} already existed.
  9. Codenames Q: {query}
  10. Ensure to audit ALL permissions for {old} and {new}.
  11. """
  12. def update_proxy_model_permissions(apps, schema_editor, reverse=False):
  13. """
  14. Update the content_type of proxy model permissions to use the ContentType
  15. of the proxy model.
  16. """
  17. style = color_style()
  18. Permission = apps.get_model('auth', 'Permission')
  19. ContentType = apps.get_model('contenttypes', 'ContentType')
  20. for Model in apps.get_models():
  21. opts = Model._meta
  22. if not opts.proxy:
  23. continue
  24. proxy_default_permissions_codenames = [
  25. '%s_%s' % (action, opts.model_name)
  26. for action in opts.default_permissions
  27. ]
  28. permissions_query = Q(codename__in=proxy_default_permissions_codenames)
  29. for codename, name in opts.permissions:
  30. permissions_query = permissions_query | Q(codename=codename, name=name)
  31. concrete_content_type = ContentType.objects.get_for_model(Model, for_concrete_model=True)
  32. proxy_content_type = ContentType.objects.get_for_model(Model, for_concrete_model=False)
  33. old_content_type = proxy_content_type if reverse else concrete_content_type
  34. new_content_type = concrete_content_type if reverse else proxy_content_type
  35. try:
  36. with transaction.atomic():
  37. Permission.objects.filter(
  38. permissions_query,
  39. content_type=old_content_type,
  40. ).update(content_type=new_content_type)
  41. except IntegrityError:
  42. old = '{}_{}'.format(old_content_type.app_label, old_content_type.model)
  43. new = '{}_{}'.format(new_content_type.app_label, new_content_type.model)
  44. sys.stdout.write(style.WARNING(WARNING.format(old=old, new=new, query=permissions_query)))
  45. def revert_proxy_model_permissions(apps, schema_editor):
  46. """
  47. Update the content_type of proxy model permissions to use the ContentType
  48. of the concrete model.
  49. """
  50. update_proxy_model_permissions(apps, schema_editor, reverse=True)
  51. class Migration(migrations.Migration):
  52. dependencies = [
  53. ('auth', '0010_alter_group_name_max_length'),
  54. ('contenttypes', '0002_remove_content_type_name'),
  55. ]
  56. operations = [
  57. migrations.RunPython(update_proxy_model_permissions, revert_proxy_model_permissions),
  58. ]