diff options
| author | Peter Inglesby <peter.inglesby@gmail.com> | 2018-07-13 22:54:47 +0100 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2018-07-13 17:54:47 -0400 |
| commit | 312eb5cb11d09c0c41b2740e2e9aef838d60c8b5 (patch) | |
| tree | 00dec6ddb620204930bc2c870e1bb73c5bb87973 /tests | |
| parent | 8f75d21a2e6d255848ae441d858c6ea819e3d100 (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.json | 20 | ||||
| -rw-r--r-- | tests/fixtures/fixtures/forward_reference_m2m.json | 23 | ||||
| -rw-r--r-- | tests/fixtures/models.py | 18 | ||||
| -rw-r--r-- | tests/fixtures/tests.py | 21 | ||||
| -rw-r--r-- | tests/serializers/models/natural.py | 18 | ||||
| -rw-r--r-- | tests/serializers/test_natural.py | 95 |
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) |
