瀏覽代碼

Fixed #32420 -- Fixed detecting primary key values in deserialization when PK is also a FK.

Mikolaj Rybinski 4 年之前
父節點
當前提交
8e90560aa8
共有 3 個文件被更改,包括 36 次插入3 次删除
  1. 1 1
      django/core/serializers/base.py
  2. 14 0
      tests/serializers/models/natural.py
  3. 21 2
      tests/serializers/test_natural.py

+ 1 - 1
django/core/serializers/base.py

@@ -257,7 +257,7 @@ def build_instance(Model, data, db):
     natural keys, try to retrieve it from the database.
     """
     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
             hasattr(Model, 'natural_key')):
         natural_key = Model(**data).natural_key()

+ 14 - 0
tests/serializers/models/natural.py

@@ -53,3 +53,17 @@ class NaturalPKWithDefault(models.Model):
 
     def natural_key(self):
         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.')

+ 21 - 2
tests/serializers/test_natural.py

@@ -3,8 +3,8 @@ from django.db import connection
 from django.test import TestCase
 
 from .models import (
-    Child, FKDataNaturalKey, NaturalKeyAnchor, NaturalKeyThing,
-    NaturalPKWithDefault,
+    Child, FKAsPKNoNaturalKey, FKDataNaturalKey, NaturalKeyAnchor,
+    NaturalKeyThing, NaturalPKWithDefault,
 )
 from .tests import register_tests
 
@@ -200,6 +200,20 @@ def pk_with_default(self, format):
     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
 register_tests(NaturalKeySerializerTests, 'test_%s_natural_key_serializer', natural_key_serializer_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_m2m_errors', forward_ref_m2m_with_error_test)
 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,
+)