summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorPeter Inglesby <peter.inglesby@gmail.com>2018-07-13 22:54:47 +0100
committerTim Graham <timograham@gmail.com>2018-07-13 17:54:47 -0400
commit312eb5cb11d09c0c41b2740e2e9aef838d60c8b5 (patch)
tree00dec6ddb620204930bc2c870e1bb73c5bb87973 /tests
parent8f75d21a2e6d255848ae441d858c6ea819e3d100 (diff)
Fixed #26291 -- Allowed loaddata to handle forward references in natural_key fixtures.
Diffstat (limited to 'tests')
-rw-r--r--tests/fixtures/fixtures/forward_reference_fk.json20
-rw-r--r--tests/fixtures/fixtures/forward_reference_m2m.json23
-rw-r--r--tests/fixtures/models.py18
-rw-r--r--tests/fixtures/tests.py21
-rw-r--r--tests/serializers/models/natural.py18
-rw-r--r--tests/serializers/test_natural.py95
6 files changed, 193 insertions, 2 deletions
diff --git a/tests/fixtures/fixtures/forward_reference_fk.json b/tests/fixtures/fixtures/forward_reference_fk.json
new file mode 100644
index 0000000000..d3122c8823
--- /dev/null
+++ b/tests/fixtures/fixtures/forward_reference_fk.json
@@ -0,0 +1,20 @@
+[
+ {
+ "model": "fixtures.naturalkeything",
+ "fields": {
+ "key": "t1",
+ "other_thing": [
+ "t2"
+ ]
+ }
+ },
+ {
+ "model": "fixtures.naturalkeything",
+ "fields": {
+ "key": "t2",
+ "other_thing": [
+ "t1"
+ ]
+ }
+ }
+]
diff --git a/tests/fixtures/fixtures/forward_reference_m2m.json b/tests/fixtures/fixtures/forward_reference_m2m.json
new file mode 100644
index 0000000000..9e0f18e294
--- /dev/null
+++ b/tests/fixtures/fixtures/forward_reference_m2m.json
@@ -0,0 +1,23 @@
+[
+ {
+ "model": "fixtures.naturalkeything",
+ "fields": {
+ "key": "t1",
+ "other_things": [
+ ["t2"], ["t3"]
+ ]
+ }
+ },
+ {
+ "model": "fixtures.naturalkeything",
+ "fields": {
+ "key": "t2"
+ }
+ },
+ {
+ "model": "fixtures.naturalkeything",
+ "fields": {
+ "key": "t3"
+ }
+ }
+]
diff --git a/tests/fixtures/models.py b/tests/fixtures/models.py
index 07ef1587d9..be6674fa61 100644
--- a/tests/fixtures/models.py
+++ b/tests/fixtures/models.py
@@ -116,3 +116,21 @@ class Book(models.Model):
class PrimaryKeyUUIDModel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
+
+
+class NaturalKeyThing(models.Model):
+ key = models.CharField(max_length=100)
+ other_thing = models.ForeignKey('NaturalKeyThing', on_delete=models.CASCADE, null=True)
+ other_things = models.ManyToManyField('NaturalKeyThing', related_name='thing_m2m_set')
+
+ class Manager(models.Manager):
+ def get_by_natural_key(self, key):
+ return self.get(key=key)
+
+ objects = Manager()
+
+ def natural_key(self):
+ return (self.key,)
+
+ def __str__(self):
+ return self.key
diff --git a/tests/fixtures/tests.py b/tests/fixtures/tests.py
index d48062f8dd..37b21fa296 100644
--- a/tests/fixtures/tests.py
+++ b/tests/fixtures/tests.py
@@ -17,7 +17,8 @@ from django.db import IntegrityError, connection
from django.test import TestCase, TransactionTestCase, skipUnlessDBFeature
from .models import (
- Article, Category, PrimaryKeyUUIDModel, ProxySpy, Spy, Tag, Visa,
+ Article, Category, NaturalKeyThing, PrimaryKeyUUIDModel, ProxySpy, Spy,
+ Tag, Visa,
)
@@ -780,3 +781,21 @@ class FixtureTransactionTests(DumpDataAssertMixin, TransactionTestCase):
'<Article: Time to reform copyright>',
'<Article: Poker has no place on ESPN>',
])
+
+
+class ForwardReferenceTests(TestCase):
+ def test_forward_reference_fk(self):
+ management.call_command('loaddata', 'forward_reference_fk.json', verbosity=0)
+ self.assertEqual(NaturalKeyThing.objects.count(), 2)
+ t1, t2 = NaturalKeyThing.objects.all()
+ self.assertEqual(t1.other_thing, t2)
+ self.assertEqual(t2.other_thing, t1)
+
+ def test_forward_reference_m2m(self):
+ management.call_command('loaddata', 'forward_reference_m2m.json', verbosity=0)
+ self.assertEqual(NaturalKeyThing.objects.count(), 3)
+ t1 = NaturalKeyThing.objects.get_by_natural_key('t1')
+ self.assertQuerysetEqual(
+ t1.other_things.order_by('key'),
+ ['<NaturalKeyThing: t2>', '<NaturalKeyThing: t3>']
+ )
diff --git a/tests/serializers/models/natural.py b/tests/serializers/models/natural.py
index b50956692e..cd24b67f0a 100644
--- a/tests/serializers/models/natural.py
+++ b/tests/serializers/models/natural.py
@@ -19,3 +19,21 @@ class NaturalKeyAnchor(models.Model):
class FKDataNaturalKey(models.Model):
data = models.ForeignKey(NaturalKeyAnchor, models.SET_NULL, null=True)
+
+
+class NaturalKeyThing(models.Model):
+ key = models.CharField(max_length=100)
+ other_thing = models.ForeignKey('NaturalKeyThing', on_delete=models.CASCADE, null=True)
+ other_things = models.ManyToManyField('NaturalKeyThing', related_name='thing_m2m_set')
+
+ class Manager(models.Manager):
+ def get_by_natural_key(self, key):
+ return self.get(key=key)
+
+ objects = Manager()
+
+ def natural_key(self):
+ return (self.key,)
+
+ def __str__(self):
+ return self.key
diff --git a/tests/serializers/test_natural.py b/tests/serializers/test_natural.py
index 776f554a1c..7e9e9382da 100644
--- a/tests/serializers/test_natural.py
+++ b/tests/serializers/test_natural.py
@@ -2,7 +2,7 @@ from django.core import serializers
from django.db import connection
from django.test import TestCase
-from .models import Child, FKDataNaturalKey, NaturalKeyAnchor
+from .models import Child, FKDataNaturalKey, NaturalKeyAnchor, NaturalKeyThing
from .tests import register_tests
@@ -93,7 +93,100 @@ def natural_pk_mti_test(self, format):
self.assertEqual(child.child_data, child.parent_data)
+def forward_ref_fk_test(self, format):
+ t1 = NaturalKeyThing.objects.create(key='t1')
+ t2 = NaturalKeyThing.objects.create(key='t2', other_thing=t1)
+ t1.other_thing = t2
+ t1.save()
+ string_data = serializers.serialize(
+ format, [t1, t2], use_natural_primary_keys=True,
+ use_natural_foreign_keys=True,
+ )
+ NaturalKeyThing.objects.all().delete()
+ objs_with_deferred_fields = []
+ for obj in serializers.deserialize(format, string_data, handle_forward_references=True):
+ obj.save()
+ if obj.deferred_fields:
+ objs_with_deferred_fields.append(obj)
+ for obj in objs_with_deferred_fields:
+ obj.save_deferred_fields()
+ t1 = NaturalKeyThing.objects.get(key='t1')
+ t2 = NaturalKeyThing.objects.get(key='t2')
+ self.assertEqual(t1.other_thing, t2)
+ self.assertEqual(t2.other_thing, t1)
+
+
+def forward_ref_fk_with_error_test(self, format):
+ t1 = NaturalKeyThing.objects.create(key='t1')
+ t2 = NaturalKeyThing.objects.create(key='t2', other_thing=t1)
+ t1.other_thing = t2
+ t1.save()
+ string_data = serializers.serialize(
+ format, [t1], use_natural_primary_keys=True,
+ use_natural_foreign_keys=True,
+ )
+ NaturalKeyThing.objects.all().delete()
+ objs_with_deferred_fields = []
+ for obj in serializers.deserialize(format, string_data, handle_forward_references=True):
+ obj.save()
+ if obj.deferred_fields:
+ objs_with_deferred_fields.append(obj)
+ obj = objs_with_deferred_fields[0]
+ msg = 'NaturalKeyThing matching query does not exist'
+ with self.assertRaisesMessage(serializers.base.DeserializationError, msg):
+ obj.save_deferred_fields()
+
+
+def forward_ref_m2m_test(self, format):
+ t1 = NaturalKeyThing.objects.create(key='t1')
+ t2 = NaturalKeyThing.objects.create(key='t2')
+ t3 = NaturalKeyThing.objects.create(key='t3')
+ t1.other_things.set([t2, t3])
+ string_data = serializers.serialize(
+ format, [t1, t2, t3], use_natural_primary_keys=True,
+ use_natural_foreign_keys=True,
+ )
+ NaturalKeyThing.objects.all().delete()
+ objs_with_deferred_fields = []
+ for obj in serializers.deserialize(format, string_data, handle_forward_references=True):
+ obj.save()
+ if obj.deferred_fields:
+ objs_with_deferred_fields.append(obj)
+ for obj in objs_with_deferred_fields:
+ obj.save_deferred_fields()
+ t1 = NaturalKeyThing.objects.get(key='t1')
+ t2 = NaturalKeyThing.objects.get(key='t2')
+ t3 = NaturalKeyThing.objects.get(key='t3')
+ self.assertCountEqual(t1.other_things.all(), [t2, t3])
+
+
+def forward_ref_m2m_with_error_test(self, format):
+ t1 = NaturalKeyThing.objects.create(key='t1')
+ t2 = NaturalKeyThing.objects.create(key='t2')
+ t3 = NaturalKeyThing.objects.create(key='t3')
+ t1.other_things.set([t2, t3])
+ t1.save()
+ string_data = serializers.serialize(
+ format, [t1, t2], use_natural_primary_keys=True,
+ use_natural_foreign_keys=True,
+ )
+ NaturalKeyThing.objects.all().delete()
+ objs_with_deferred_fields = []
+ for obj in serializers.deserialize(format, string_data, handle_forward_references=True):
+ obj.save()
+ if obj.deferred_fields:
+ objs_with_deferred_fields.append(obj)
+ obj = objs_with_deferred_fields[0]
+ msg = 'NaturalKeyThing matching query does not exist'
+ with self.assertRaisesMessage(serializers.base.DeserializationError, msg):
+ obj.save_deferred_fields()
+
+
# 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)
register_tests(NaturalKeySerializerTests, 'test_%s_serializer_natural_pks_mti', natural_pk_mti_test)
+register_tests(NaturalKeySerializerTests, 'test_%s_forward_references_fks', forward_ref_fk_test)
+register_tests(NaturalKeySerializerTests, 'test_%s_forward_references_fk_errors', forward_ref_fk_with_error_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)