summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikolaj Rybinski <mikolaj.rybinski@id.ethz.ch>2021-02-04 18:19:14 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-02-05 14:19:10 +0100
commitd881a0ea3b733a64cfb5fe19561bb01479669ed6 (patch)
tree73df5c9e39fbdf2674f3b7de0b0e742c6ed2270f
parentf490cde15d112b2e6d35d16bcea7ce4e0a29e5d8 (diff)
downloaddjango-d881a0ea3b733a64cfb5fe19561bb01479669ed6.tar.gz
[3.2.x] Fixed #32420 -- Fixed detecting primary key values in deserialization when PK is also a FK.
Backport of 8e90560aa8868a42bb8eda6273595bf0932a6090 from master
-rw-r--r--django/core/serializers/base.py2
-rw-r--r--tests/serializers/models/natural.py14
-rw-r--r--tests/serializers/test_natural.py23
3 files changed, 36 insertions, 3 deletions
diff --git a/django/core/serializers/base.py b/django/core/serializers/base.py
index 72565236c4..3fee7893df 100644
--- a/django/core/serializers/base.py
+++ b/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()
diff --git a/tests/serializers/models/natural.py b/tests/serializers/models/natural.py
index 88bfed566b..d062d7a45b 100644
--- a/tests/serializers/models/natural.py
+++ b/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.')
diff --git a/tests/serializers/test_natural.py b/tests/serializers/test_natural.py
index 3b4218bcc9..7d05f3a71f 100644
--- a/tests/serializers/test_natural.py
+++ b/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,
+)