Fix #17879: Corrected regression in python (inherited by yaml and json) serializer that prevented serializing model instances with null FK ref to a model when serializing with natural keys. Thanks danfairs and tmitchell.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17685 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
2f520139be
commit
20c69c5e51
1
AUTHORS
1
AUTHORS
|
@ -369,6 +369,7 @@ answer newbie questions, and generally made Django that much better:
|
|||
Slawek Mikula <slawek dot mikula at gmail dot com>
|
||||
Shawn Milochik <shawn@milochik.com>
|
||||
mitakummaa@gmail.com
|
||||
Taylor Mitchell <taylor.mitchell@gmail.com>
|
||||
mmarshall
|
||||
Andreas Mock <andreas.mock@web.de>
|
||||
Reza Mohammadi <reza@zeerak.ir>
|
||||
|
|
|
@ -47,7 +47,10 @@ class Serializer(base.Serializer):
|
|||
def handle_fk_field(self, obj, field):
|
||||
if self.use_natural_keys and hasattr(field.rel.to, 'natural_key'):
|
||||
related = getattr(obj, field.name)
|
||||
value = related.natural_key()
|
||||
if related:
|
||||
value = related.natural_key()
|
||||
else:
|
||||
value = None
|
||||
else:
|
||||
value = getattr(obj, field.get_attname())
|
||||
self._current[field.name] = value
|
||||
|
|
|
@ -111,6 +111,18 @@ class Anchor(models.Model):
|
|||
class Meta:
|
||||
ordering = ('id',)
|
||||
|
||||
class NaturalKeyAnchorManager(models.Manager):
|
||||
def get_by_natural_key(self, data):
|
||||
return self.get(data=data)
|
||||
|
||||
class NaturalKeyAnchor(models.Model):
|
||||
objects = NaturalKeyAnchorManager()
|
||||
|
||||
data = models.CharField(max_length=100, unique=True)
|
||||
|
||||
def natural_key(self):
|
||||
return (self.data,)
|
||||
|
||||
class UniqueAnchor(models.Model):
|
||||
"""This is a model that can be used as
|
||||
something for other models to point at"""
|
||||
|
@ -120,6 +132,9 @@ class UniqueAnchor(models.Model):
|
|||
class FKData(models.Model):
|
||||
data = models.ForeignKey(Anchor, null=True)
|
||||
|
||||
class FKDataNaturalKey(models.Model):
|
||||
data = models.ForeignKey(NaturalKeyAnchor, null=True)
|
||||
|
||||
class M2MData(models.Model):
|
||||
data = models.ManyToManyField(Anchor, null=True)
|
||||
|
||||
|
@ -272,3 +287,4 @@ class LengthModel(models.Model):
|
|||
|
||||
def __len__(self):
|
||||
return self.data
|
||||
|
||||
|
|
|
@ -42,7 +42,8 @@ from .models import (BooleanData, CharData, DateData, DateTimeData, EmailData,
|
|||
PositiveSmallIntegerPKData, SlugPKData, SmallPKData, USStatePKData,
|
||||
AutoNowDateTimeData, ModifyingSaveData, InheritAbstractModel, BaseModel,
|
||||
ExplicitInheritBaseModel, InheritBaseModel, ProxyBaseModel,
|
||||
ProxyProxyBaseModel, BigIntegerData, LengthModel, Tag, ComplexModel)
|
||||
ProxyProxyBaseModel, BigIntegerData, LengthModel, Tag, ComplexModel,
|
||||
NaturalKeyAnchor, FKDataNaturalKey)
|
||||
|
||||
# A set of functions that can be used to recreate
|
||||
# test data objects of various kinds.
|
||||
|
@ -353,6 +354,12 @@ The end."""),
|
|||
(data_obj, 1005, LengthModel, 1),
|
||||
]
|
||||
|
||||
natural_key_test_data = [
|
||||
(data_obj, 1100, NaturalKeyAnchor, "Natural Key Anghor"),
|
||||
(fk_obj, 1101, FKDataNaturalKey, 1100),
|
||||
(fk_obj, 1102, FKDataNaturalKey, None),
|
||||
]
|
||||
|
||||
# Because Oracle treats the empty string as NULL, Oracle is expected to fail
|
||||
# when field.empty_strings_allowed is True and the value is None; skip these
|
||||
# tests.
|
||||
|
@ -452,6 +459,35 @@ def serializerTest(format, self):
|
|||
for klass, count in instance_count.items():
|
||||
self.assertEqual(count, klass.objects.count())
|
||||
|
||||
def naturalKeySerializerTest(format, self):
|
||||
# Create all the objects defined in the test data
|
||||
objects = []
|
||||
instance_count = {}
|
||||
for (func, pk, klass, datum) in natural_key_test_data:
|
||||
with connection.constraint_checks_disabled():
|
||||
objects.extend(func[0](pk, klass, datum))
|
||||
|
||||
# Get a count of the number of objects created for each class
|
||||
for klass in instance_count:
|
||||
instance_count[klass] = klass.objects.count()
|
||||
|
||||
# Serialize the test database
|
||||
serialized_data = serializers.serialize(format, objects, indent=2,
|
||||
use_natural_keys=True)
|
||||
|
||||
for obj in serializers.deserialize(format, serialized_data):
|
||||
obj.save()
|
||||
|
||||
# Assert that the deserialized data is the same
|
||||
# as the original source
|
||||
for (func, pk, klass, datum) in natural_key_test_data:
|
||||
func[1](self, pk, klass, datum)
|
||||
|
||||
# Assert that the number of objects deserialized is the
|
||||
# same as the number that was serialized.
|
||||
for klass, count in instance_count.items():
|
||||
self.assertEqual(count, klass.objects.count())
|
||||
|
||||
def fieldsTest(format, self):
|
||||
obj = ComplexModel(field1='first', field2='second', field3='third')
|
||||
obj.save_base(raw=True)
|
||||
|
@ -482,6 +518,8 @@ def streamTest(format, self):
|
|||
|
||||
for format in serializers.get_serializer_formats():
|
||||
setattr(SerializerTests, 'test_' + format + '_serializer', curry(serializerTest, format))
|
||||
setattr(SerializerTests, 'test_' + format + '_natural_key_serializer', curry(naturalKeySerializerTest, format))
|
||||
setattr(SerializerTests, 'test_' + format + '_serializer_fields', curry(fieldsTest, format))
|
||||
if format != 'python':
|
||||
setattr(SerializerTests, 'test_' + format + '_serializer_stream', curry(streamTest, format))
|
||||
|
||||
|
|
Loading…
Reference in New Issue