summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Johnson <me@adamj.eu>2024-05-10 12:06:27 +0100
committerSarah Boyce <42296566+sarahboyce@users.noreply.github.com>2024-05-13 08:34:57 +0200
commitd2c5a30e5a8595d06c4a70ff0f66032fee0d3c8e (patch)
tree3dc4fb58409e0bde834fe7c8060fd84022360beb
parent1a36dce9c5e0627d46582829d7abd47ed872e3aa (diff)
Fixed #35408 -- Optimized post-migrate permission creation.
co-authored-by: Mariusz Felisiak <felisiak.mariusz@gmail.com>
-rw-r--r--django/contrib/auth/management/__init__.py50
-rw-r--r--tests/auth_tests/test_management.py2
2 files changed, 24 insertions, 28 deletions
diff --git a/django/contrib/auth/management/__init__.py b/django/contrib/auth/management/__init__.py
index b29a980cb2..c40f2aa69d 100644
--- a/django/contrib/auth/management/__init__.py
+++ b/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:
diff --git a/tests/auth_tests/test_management.py b/tests/auth_tests/test_management.py
index 0cc56b6760..5765c50034 100644
--- a/tests/auth_tests/test_management.py
+++ b/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)