mirror of
https://github.com/django/django.git
synced 2025-10-31 09:41:08 +00:00
Fixed #31051 -- Allowed dumpdata to handle circular references in natural keys.
Since #26291 forward references in natural keys are properly handled by loaddata, so sorting depenencies in dumpdata doesn't need to break on cycles. This patch allows circular references in natural keys by breaking sort_depenencies() on loops.
This commit is contained in:
committed by
Mariusz Felisiak
parent
590957a0eb
commit
4f216e4f8e
16
tests/fixtures/fixtures/circular_reference_natural_key.json
vendored
Normal file
16
tests/fixtures/fixtures/circular_reference_natural_key.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
[
|
||||
{
|
||||
"model": "fixtures.circulara",
|
||||
"fields": {
|
||||
"key": "x",
|
||||
"obj": ["y"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "fixtures.circularb",
|
||||
"fields": {
|
||||
"key": "y",
|
||||
"obj": ["x"]
|
||||
}
|
||||
}
|
||||
]
|
||||
21
tests/fixtures/models.py
vendored
21
tests/fixtures/models.py
vendored
@@ -118,16 +118,17 @@ class PrimaryKeyUUIDModel(models.Model):
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
|
||||
|
||||
|
||||
class NaturalKeyManager(models.Manager):
|
||||
def get_by_natural_key(self, key):
|
||||
return self.get(key=key)
|
||||
|
||||
|
||||
class NaturalKeyThing(models.Model):
|
||||
key = models.CharField(max_length=100, unique=True)
|
||||
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()
|
||||
objects = NaturalKeyManager()
|
||||
|
||||
def natural_key(self):
|
||||
return (self.key,)
|
||||
@@ -140,7 +141,17 @@ class CircularA(models.Model):
|
||||
key = models.CharField(max_length=3, unique=True)
|
||||
obj = models.ForeignKey('CircularB', models.SET_NULL, null=True)
|
||||
|
||||
objects = NaturalKeyManager()
|
||||
|
||||
def natural_key(self):
|
||||
return (self.key,)
|
||||
|
||||
|
||||
class CircularB(models.Model):
|
||||
key = models.CharField(max_length=3, unique=True)
|
||||
obj = models.ForeignKey('CircularA', models.SET_NULL, null=True)
|
||||
|
||||
objects = NaturalKeyManager()
|
||||
|
||||
def natural_key(self):
|
||||
return (self.key,)
|
||||
|
||||
20
tests/fixtures/tests.py
vendored
20
tests/fixtures/tests.py
vendored
@@ -880,3 +880,23 @@ class CircularReferenceTests(DumpDataAssertMixin, TestCase):
|
||||
'{"model": "fixtures.circularb", "pk": 1, '
|
||||
'"fields": {"key": "y", "obj": 1}}]',
|
||||
)
|
||||
|
||||
def test_circular_reference_natural_key(self):
|
||||
management.call_command(
|
||||
'loaddata',
|
||||
'circular_reference_natural_key.json',
|
||||
verbosity=0,
|
||||
)
|
||||
obj_a = CircularA.objects.get()
|
||||
obj_b = CircularB.objects.get()
|
||||
self.assertEqual(obj_a.obj, obj_b)
|
||||
self.assertEqual(obj_b.obj, obj_a)
|
||||
self._dumpdata_assert(
|
||||
['fixtures'],
|
||||
'[{"model": "fixtures.circulara", '
|
||||
'"fields": {"key": "x", "obj": ["y"]}}, '
|
||||
'{"model": "fixtures.circularb", '
|
||||
'"fields": {"key": "y", "obj": ["x"]}}]',
|
||||
natural_primary_keys=True,
|
||||
natural_foreign_keys=True,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user