mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #35408 -- Optimized post-migrate permission creation.
co-authored-by: Mariusz Felisiak <felisiak.mariusz@gmail.com>
This commit is contained in:
		
				
					committed by
					
						 Sarah Boyce
						Sarah Boyce
					
				
			
			
				
	
			
			
			
						parent
						
							1a36dce9c5
						
					
				
				
					commit
					d2c5a30e5a
				
			| @@ -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,48 +69,37 @@ 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 | ||||||
|     # a list of the ones we're going to create. |     # a list of the ones we're going to create. | ||||||
|     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] | ||||||
|  |         for codename, name in _get_all_permissions(model._meta): | ||||||
|  |             if (ctype.pk, codename) not in all_perms: | ||||||
|                 permission = Permission() |                 permission = Permission() | ||||||
|                 permission._state.db = using |                 permission._state.db = using | ||||||
|                 permission.codename = codename |                 permission.codename = codename | ||||||
|                 permission.name = name |                 permission.name = name | ||||||
|             permission.content_type = ct |                 permission.content_type = ctype | ||||||
|                 perms.append(permission) |                 perms.append(permission) | ||||||
|  |  | ||||||
|     Permission.objects.using(using).bulk_create(perms) |     Permission.objects.using(using).bulk_create(perms) | ||||||
|   | |||||||
| @@ -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) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user