소스 검색

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

co-authored-by: Mariusz Felisiak <felisiak.mariusz@gmail.com>
Adam Johnson 10 달 전
부모
커밋
d2c5a30e5a
2개의 변경된 파일24개의 추가작업 그리고 28개의 파일을 삭제
  1. 23 27
      django/contrib/auth/management/__init__.py
  2. 1 1
      tests/auth_tests/test_management.py

+ 23 - 27
django/contrib/auth/management/__init__.py

@@ -46,6 +46,13 @@ def create_permissions(
     if not app_config.models_module:
         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
     # 'django.contrib.auth' is in INSTALLED_APPS before
     # 'django.contrib.contenttypes'.
@@ -62,28 +69,15 @@ def create_permissions(
     try:
         app_config = apps.get_app_config(app_label)
         ContentType = apps.get_model("contenttypes", "ContentType")
-        Permission = apps.get_model("auth", "Permission")
     except LookupError:
         return
 
-    if not router.allow_migrate_model(using, Permission):
-        return
-
-    # This will hold the permissions we're looking for as
-    # (content_type, (codename, name))
-    searched_perms = []
-    # 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
-        )
+    models = list(app_config.get_models())
 
-        ctypes.add(ctype)
-        for perm in _get_all_permissions(klass._meta):
-            searched_perms.append((ctype, perm))
+    # Grab all the ContentTypes.
+    ctypes = ContentType.objects.db_manager(using).get_for_models(
+        *models, for_concrete_models=False
+    )
 
     # 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
@@ -91,20 +85,22 @@ def create_permissions(
     all_perms = set(
         Permission.objects.using(using)
         .filter(
-            content_type__in=ctypes,
+            content_type__in=set(ctypes.values()),
         )
         .values_list("content_type", "codename")
     )
 
     perms = []
-    for ct, (codename, name) in searched_perms:
-        if (ct.pk, codename) not in all_perms:
-            permission = Permission()
-            permission._state.db = using
-            permission.codename = codename
-            permission.name = name
-            permission.content_type = ct
-            perms.append(permission)
+    for model in models:
+        ctype = ctypes[model]
+        for codename, name in _get_all_permissions(model._meta):
+            if (ctype.pk, codename) not in all_perms:
+                permission = Permission()
+                permission._state.db = using
+                permission.codename = codename
+                permission.name = name
+                permission.content_type = ctype
+                perms.append(permission)
 
     Permission.objects.using(using).bulk_create(perms)
     if verbosity >= 2:

+ 1 - 1
tests/auth_tests/test_management.py

@@ -1528,7 +1528,7 @@ class CreatePermissionsMultipleDatabasesTests(TestCase):
 
     def test_set_permissions_fk_to_using_parameter(self):
         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")
         self.assertIn("INSERT INTO", captured_queries[-1]["sql"].upper())
         self.assertGreater(Permission.objects.using("other").count(), 0)