mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	[3.2.x] Fixed #32420 -- Fixed detecting primary key values in deserialization when PK is also a FK.
Backport of 8e90560aa8 from master
			
			
This commit is contained in:
		
				
					committed by
					
						 Mariusz Felisiak
						Mariusz Felisiak
					
				
			
			
				
	
			
			
			
						parent
						
							f490cde15d
						
					
				
				
					commit
					d881a0ea3b
				
			| @@ -257,7 +257,7 @@ def build_instance(Model, data, db): | |||||||
|     natural keys, try to retrieve it from the database. |     natural keys, try to retrieve it from the database. | ||||||
|     """ |     """ | ||||||
|     default_manager = Model._meta.default_manager |     default_manager = Model._meta.default_manager | ||||||
|     pk = data.get(Model._meta.pk.name) |     pk = data.get(Model._meta.pk.attname) | ||||||
|     if (pk is None and hasattr(default_manager, 'get_by_natural_key') and |     if (pk is None and hasattr(default_manager, 'get_by_natural_key') and | ||||||
|             hasattr(Model, 'natural_key')): |             hasattr(Model, 'natural_key')): | ||||||
|         natural_key = Model(**data).natural_key() |         natural_key = Model(**data).natural_key() | ||||||
|   | |||||||
| @@ -53,3 +53,17 @@ class NaturalPKWithDefault(models.Model): | |||||||
|  |  | ||||||
|     def natural_key(self): |     def natural_key(self): | ||||||
|         return (self.name,) |         return (self.name,) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class FKAsPKNoNaturalKeyManager(models.Manager): | ||||||
|  |     def get_by_natural_key(self, *args, **kwargs): | ||||||
|  |         return super().get_by_natural_key(*args, **kwargs) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class FKAsPKNoNaturalKey(models.Model): | ||||||
|  |     pk_fk = models.ForeignKey(NaturalKeyAnchor, on_delete=models.CASCADE, primary_key=True) | ||||||
|  |  | ||||||
|  |     objects = FKAsPKNoNaturalKeyManager() | ||||||
|  |  | ||||||
|  |     def natural_key(self): | ||||||
|  |         raise NotImplementedError('This method was not expected to be called.') | ||||||
|   | |||||||
| @@ -3,8 +3,8 @@ from django.db import connection | |||||||
| from django.test import TestCase | from django.test import TestCase | ||||||
|  |  | ||||||
| from .models import ( | from .models import ( | ||||||
|     Child, FKDataNaturalKey, NaturalKeyAnchor, NaturalKeyThing, |     Child, FKAsPKNoNaturalKey, FKDataNaturalKey, NaturalKeyAnchor, | ||||||
|     NaturalPKWithDefault, |     NaturalKeyThing, NaturalPKWithDefault, | ||||||
| ) | ) | ||||||
| from .tests import register_tests | from .tests import register_tests | ||||||
|  |  | ||||||
| @@ -200,6 +200,20 @@ def pk_with_default(self, format): | |||||||
|     self.assertEqual(objs[0].object.pk, obj.pk) |     self.assertEqual(objs[0].object.pk, obj.pk) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def fk_as_pk_natural_key_not_called(self, format): | ||||||
|  |     """ | ||||||
|  |     The deserializer doesn't rely on natural keys when a model has a custom | ||||||
|  |     primary key that is a ForeignKey. | ||||||
|  |     """ | ||||||
|  |     o1 = NaturalKeyAnchor.objects.create(data='978-1590599969') | ||||||
|  |     o2 = FKAsPKNoNaturalKey.objects.create(pk_fk=o1) | ||||||
|  |     serialized_data = serializers.serialize(format, [o1, o2]) | ||||||
|  |     deserialized_objects = list(serializers.deserialize(format, serialized_data)) | ||||||
|  |     self.assertEqual(len(deserialized_objects), 2) | ||||||
|  |     for obj in deserialized_objects: | ||||||
|  |         self.assertEqual(obj.object.pk, o1.pk) | ||||||
|  |  | ||||||
|  |  | ||||||
| # Dynamically register tests for each serializer | # Dynamically register tests for each serializer | ||||||
| register_tests(NaturalKeySerializerTests, 'test_%s_natural_key_serializer', natural_key_serializer_test) | register_tests(NaturalKeySerializerTests, 'test_%s_natural_key_serializer', natural_key_serializer_test) | ||||||
| register_tests(NaturalKeySerializerTests, 'test_%s_serializer_natural_keys', natural_key_test) | register_tests(NaturalKeySerializerTests, 'test_%s_serializer_natural_keys', natural_key_test) | ||||||
| @@ -209,3 +223,8 @@ register_tests(NaturalKeySerializerTests, 'test_%s_forward_references_fk_errors' | |||||||
| register_tests(NaturalKeySerializerTests, 'test_%s_forward_references_m2ms', forward_ref_m2m_test) | register_tests(NaturalKeySerializerTests, 'test_%s_forward_references_m2ms', forward_ref_m2m_test) | ||||||
| register_tests(NaturalKeySerializerTests, 'test_%s_forward_references_m2m_errors', forward_ref_m2m_with_error_test) | register_tests(NaturalKeySerializerTests, 'test_%s_forward_references_m2m_errors', forward_ref_m2m_with_error_test) | ||||||
| register_tests(NaturalKeySerializerTests, 'test_%s_pk_with_default', pk_with_default) | register_tests(NaturalKeySerializerTests, 'test_%s_pk_with_default', pk_with_default) | ||||||
|  | register_tests( | ||||||
|  |     NaturalKeySerializerTests, | ||||||
|  |     'test_%s_fk_as_pk_natural_key_not_called', | ||||||
|  |     fk_as_pk_natural_key_not_called, | ||||||
|  | ) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user