1
0
mirror of https://github.com/django/django.git synced 2025-05-05 06:27:31 +00:00

Fixed #35408 -- Optimized post-migrate permission creation.

co-authored-by: Mariusz Felisiak <felisiak.mariusz@gmail.com>
This commit is contained in:
Adam Johnson 2024-05-10 12:06:27 +01:00 committed by Sarah Boyce
parent 1a36dce9c5
commit d2c5a30e5a
2 changed files with 24 additions and 28 deletions

View File

@ -46,6 +46,13 @@ def create_permissions(
if not app_config.models_module: if not app_config.models_module:
return return
try:
Permission = apps.get_model("auth", "Permission")
except LookupError:
return
if not router.allow_migrate_model(using, Permission):
return
# Ensure that contenttypes are created for this app. Needed if # Ensure that contenttypes are created for this app. Needed if
# 'django.contrib.auth' is in INSTALLED_APPS before # 'django.contrib.auth' is in INSTALLED_APPS before
# 'django.contrib.contenttypes'. # 'django.contrib.contenttypes'.
@ -62,28 +69,15 @@ def create_permissions(
try: try:
app_config = apps.get_app_config(app_label) app_config = apps.get_app_config(app_label)
ContentType = apps.get_model("contenttypes", "ContentType") ContentType = apps.get_model("contenttypes", "ContentType")
Permission = apps.get_model("auth", "Permission")
except LookupError: except LookupError:
return return
if not router.allow_migrate_model(using, Permission): models = list(app_config.get_models())
return
# This will hold the permissions we're looking for as # Grab all the ContentTypes.
# (content_type, (codename, name)) ctypes = ContentType.objects.db_manager(using).get_for_models(
searched_perms = [] *models, for_concrete_models=False
# The codenames and ctypes that should exist. )
ctypes = set()
for klass in app_config.get_models():
# Force looking up the content types in the current database
# before creating foreign keys to them.
ctype = ContentType.objects.db_manager(using).get_for_model(
klass, for_concrete_model=False
)
ctypes.add(ctype)
for perm in _get_all_permissions(klass._meta):
searched_perms.append((ctype, perm))
# Find all the Permissions that have a content_type for a model we're # Find all the Permissions that have a content_type for a model we're
# looking for. We don't need to check for codenames since we already have # looking for. We don't need to check for codenames since we already have
@ -91,20 +85,22 @@ def create_permissions(
all_perms = set( all_perms = set(
Permission.objects.using(using) Permission.objects.using(using)
.filter( .filter(
content_type__in=ctypes, content_type__in=set(ctypes.values()),
) )
.values_list("content_type", "codename") .values_list("content_type", "codename")
) )
perms = [] perms = []
for ct, (codename, name) in searched_perms: for model in models:
if (ct.pk, codename) not in all_perms: ctype = ctypes[model]
permission = Permission() for codename, name in _get_all_permissions(model._meta):
permission._state.db = using if (ctype.pk, codename) not in all_perms:
permission.codename = codename permission = Permission()
permission.name = name permission._state.db = using
permission.content_type = ct permission.codename = codename
perms.append(permission) permission.name = name
permission.content_type = ctype
perms.append(permission)
Permission.objects.using(using).bulk_create(perms) Permission.objects.using(using).bulk_create(perms)
if verbosity >= 2: if verbosity >= 2:

View File

@ -1528,7 +1528,7 @@ class CreatePermissionsMultipleDatabasesTests(TestCase):
def test_set_permissions_fk_to_using_parameter(self): def test_set_permissions_fk_to_using_parameter(self):
Permission.objects.using("other").delete() Permission.objects.using("other").delete()
with self.assertNumQueries(6, using="other") as captured_queries: with self.assertNumQueries(4, using="other") as captured_queries:
create_permissions(apps.get_app_config("auth"), verbosity=0, using="other") create_permissions(apps.get_app_config("auth"), verbosity=0, using="other")
self.assertIn("INSERT INTO", captured_queries[-1]["sql"].upper()) self.assertIn("INSERT INTO", captured_queries[-1]["sql"].upper())
self.assertGreater(Permission.objects.using("other").count(), 0) self.assertGreater(Permission.objects.using("other").count(), 0)