mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	[5.2.x] Fixed #36373 -- Fixed select_related() crash on foreign object for a composite pk.
Thanks Jacob Walls for the report and Sarah for the in-depth review.
Backport of 8be0c0d690 from main.
			
			
This commit is contained in:
		
				
					committed by
					
						 Sarah Boyce
						Sarah Boyce
					
				
			
			
				
	
			
			
			
						parent
						
							ab5c066472
						
					
				
				
					commit
					e23dd72880
				
			| @@ -2715,7 +2715,11 @@ class RelatedPopulator: | ||||
|             ) | ||||
|  | ||||
|         self.model_cls = klass_info["model"] | ||||
|         self.pk_idx = self.init_list.index(self.model_cls._meta.pk.attname) | ||||
|         # A primary key must have all of its constituents not-NULL as | ||||
|         # NULL != NULL and thus NULL cannot be referenced through a foreign | ||||
|         # relationship. Therefore checking for a single member of the primary | ||||
|         # key is enough to determine if the referenced object exists or not. | ||||
|         self.pk_idx = self.init_list.index(self.model_cls._meta.pk_fields[0].attname) | ||||
|         self.related_populators = get_related_populators(klass_info, select, self.db) | ||||
|         self.local_setter = klass_info["local_setter"] | ||||
|         self.remote_setter = klass_info["remote_setter"] | ||||
|   | ||||
| @@ -9,4 +9,5 @@ Django 5.2.2 fixes several bugs in 5.2.1. | ||||
| Bugfixes | ||||
| ======== | ||||
|  | ||||
| * ... | ||||
| * Fixed a crash when using ``select_related`` against a ``ForeignObject`` | ||||
|   originating from a model with a ``CompositePrimaryKey`` (:ticket:`36373`). | ||||
|   | ||||
| @@ -14,17 +14,18 @@ class Token(models.Model): | ||||
|     secret = models.CharField(max_length=10, default="", blank=True) | ||||
|  | ||||
|  | ||||
| class BaseModel(models.Model): | ||||
| class AbstractUser(models.Model): | ||||
|     pk = models.CompositePrimaryKey("tenant_id", "id") | ||||
|     tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE) | ||||
|     email = models.EmailField(unique=True) | ||||
|     id = models.SmallIntegerField(unique=True) | ||||
|  | ||||
|     class Meta: | ||||
|         abstract = True | ||||
|  | ||||
|  | ||||
| class User(BaseModel): | ||||
|     email = models.EmailField(unique=True) | ||||
| class User(AbstractUser): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class Comment(models.Model): | ||||
| @@ -35,13 +36,14 @@ class Comment(models.Model): | ||||
|         related_name="comments", | ||||
|     ) | ||||
|     id = models.SmallIntegerField(unique=True, db_column="comment_id") | ||||
|     user_id = models.SmallIntegerField() | ||||
|     user_id = models.SmallIntegerField(null=True) | ||||
|     user = models.ForeignObject( | ||||
|         User, | ||||
|         on_delete=models.CASCADE, | ||||
|         from_fields=("tenant_id", "user_id"), | ||||
|         to_fields=("tenant_id", "id"), | ||||
|         related_name="comments", | ||||
|         null=True, | ||||
|     ) | ||||
|     text = models.TextField(default="", blank=True) | ||||
|     integer = models.IntegerField(default=0) | ||||
|   | ||||
| @@ -170,6 +170,14 @@ class CompositePKTests(TestCase): | ||||
|         with self.assertNumQueries(1): | ||||
|             self.assertEqual(user.email, self.user.email) | ||||
|  | ||||
|     def test_select_related(self): | ||||
|         Comment.objects.create(tenant=self.tenant, id=2) | ||||
|         with self.assertNumQueries(1): | ||||
|             comments = list(Comment.objects.select_related("user").order_by("pk")) | ||||
|             self.assertEqual(len(comments), 2) | ||||
|             self.assertEqual(comments[0].user, self.user) | ||||
|             self.assertIsNone(comments[1].user) | ||||
|  | ||||
|     def test_model_forms(self): | ||||
|         fields = ["tenant", "id", "user_id", "text", "integer"] | ||||
|         self.assertEqual(list(CommentForm.base_fields), fields) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user