Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fix #17879: Corrected regression in python (inherited by yaml and jso…

…n) 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
  • Loading branch information...
commit 20c69c5e51f1ca180978a51d64246b70f778df83 1 parent 2f52013
@kmtracey kmtracey authored
View
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>
View
5 django/core/serializers/python.py
@@ -47,7 +47,10 @@ def handle_field(self, obj, field):
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
View
16 tests/regressiontests/serializers_regress/models.py
@@ -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
+
View
40 tests/regressiontests/serializers_regress/tests.py
@@ -42,7 +42,8 @@
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 @@ def inherited_compare(testcase, pk, klass, data):
(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))
+
Please sign in to comment.
Something went wrong with that request. Please try again.