Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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
Karen Tracey authored March 12, 2012
1  AUTHORS
@@ -369,6 +369,7 @@ answer newbie questions, and generally made Django that much better:
369 369
     Slawek Mikula <slawek dot mikula at gmail dot com>
370 370
     Shawn Milochik <shawn@milochik.com>
371 371
     mitakummaa@gmail.com
  372
+    Taylor Mitchell <taylor.mitchell@gmail.com>
372 373
     mmarshall
373 374
     Andreas Mock <andreas.mock@web.de>
374 375
     Reza Mohammadi <reza@zeerak.ir>
5  django/core/serializers/python.py
@@ -47,7 +47,10 @@ def handle_field(self, obj, field):
47 47
     def handle_fk_field(self, obj, field):
48 48
         if self.use_natural_keys and hasattr(field.rel.to, 'natural_key'):
49 49
             related = getattr(obj, field.name)
50  
-            value = related.natural_key()
  50
+            if related:
  51
+                value = related.natural_key()
  52
+            else:
  53
+                value = None
51 54
         else:
52 55
             value = getattr(obj, field.get_attname())
53 56
         self._current[field.name] = value
16  tests/regressiontests/serializers_regress/models.py
@@ -111,6 +111,18 @@ class Anchor(models.Model):
111 111
     class Meta:
112 112
         ordering = ('id',)
113 113
 
  114
+class NaturalKeyAnchorManager(models.Manager):
  115
+    def get_by_natural_key(self, data):
  116
+        return self.get(data=data)
  117
+
  118
+class NaturalKeyAnchor(models.Model):
  119
+    objects = NaturalKeyAnchorManager()
  120
+
  121
+    data = models.CharField(max_length=100, unique=True)
  122
+
  123
+    def natural_key(self):
  124
+        return (self.data,)
  125
+
114 126
 class UniqueAnchor(models.Model):
115 127
     """This is a model that can be used as
116 128
     something for other models to point at"""
@@ -120,6 +132,9 @@ class UniqueAnchor(models.Model):
120 132
 class FKData(models.Model):
121 133
     data = models.ForeignKey(Anchor, null=True)
122 134
 
  135
+class FKDataNaturalKey(models.Model):
  136
+    data = models.ForeignKey(NaturalKeyAnchor, null=True)
  137
+
123 138
 class M2MData(models.Model):
124 139
     data = models.ManyToManyField(Anchor, null=True)
125 140
 
@@ -272,3 +287,4 @@ class LengthModel(models.Model):
272 287
 
273 288
     def __len__(self):
274 289
         return self.data
  290
+
40  tests/regressiontests/serializers_regress/tests.py
@@ -42,7 +42,8 @@
42 42
     PositiveSmallIntegerPKData, SlugPKData, SmallPKData, USStatePKData,
43 43
     AutoNowDateTimeData, ModifyingSaveData, InheritAbstractModel, BaseModel,
44 44
     ExplicitInheritBaseModel, InheritBaseModel, ProxyBaseModel,
45  
-    ProxyProxyBaseModel, BigIntegerData, LengthModel, Tag, ComplexModel)
  45
+    ProxyProxyBaseModel, BigIntegerData, LengthModel, Tag, ComplexModel,
  46
+    NaturalKeyAnchor, FKDataNaturalKey)
46 47
 
47 48
 # A set of functions that can be used to recreate
48 49
 # test data objects of various kinds.
@@ -353,6 +354,12 @@ def inherited_compare(testcase, pk, klass, data):
353 354
     (data_obj, 1005, LengthModel, 1),
354 355
 ]
355 356
 
  357
+natural_key_test_data = [
  358
+    (data_obj, 1100, NaturalKeyAnchor, "Natural Key Anghor"),
  359
+    (fk_obj, 1101, FKDataNaturalKey, 1100),
  360
+    (fk_obj, 1102, FKDataNaturalKey, None),
  361
+]
  362
+
356 363
 # Because Oracle treats the empty string as NULL, Oracle is expected to fail
357 364
 # when field.empty_strings_allowed is True and the value is None; skip these
358 365
 # tests.
@@ -452,6 +459,35 @@ def serializerTest(format, self):
452 459
     for klass, count in instance_count.items():
453 460
         self.assertEqual(count, klass.objects.count())
454 461
 
  462
+def naturalKeySerializerTest(format, self):
  463
+    # Create all the objects defined in the test data
  464
+    objects = []
  465
+    instance_count = {}
  466
+    for (func, pk, klass, datum) in natural_key_test_data:
  467
+        with connection.constraint_checks_disabled():
  468
+            objects.extend(func[0](pk, klass, datum))
  469
+
  470
+    # Get a count of the number of objects created for each class
  471
+    for klass in instance_count:
  472
+        instance_count[klass] = klass.objects.count()
  473
+
  474
+    # Serialize the test database
  475
+    serialized_data = serializers.serialize(format, objects, indent=2,
  476
+        use_natural_keys=True)
  477
+
  478
+    for obj in serializers.deserialize(format, serialized_data):
  479
+        obj.save()
  480
+
  481
+    # Assert that the deserialized data is the same
  482
+    # as the original source
  483
+    for (func, pk, klass, datum) in natural_key_test_data:
  484
+        func[1](self, pk, klass, datum)
  485
+
  486
+    # Assert that the number of objects deserialized is the
  487
+    # same as the number that was serialized.
  488
+    for klass, count in instance_count.items():
  489
+        self.assertEqual(count, klass.objects.count())
  490
+
455 491
 def fieldsTest(format, self):
456 492
     obj = ComplexModel(field1='first', field2='second', field3='third')
457 493
     obj.save_base(raw=True)
@@ -482,6 +518,8 @@ def streamTest(format, self):
482 518
 
483 519
 for format in serializers.get_serializer_formats():
484 520
     setattr(SerializerTests, 'test_' + format + '_serializer', curry(serializerTest, format))
  521
+    setattr(SerializerTests, 'test_' + format + '_natural_key_serializer', curry(naturalKeySerializerTest, format))
485 522
     setattr(SerializerTests, 'test_' + format + '_serializer_fields', curry(fieldsTest, format))
486 523
     if format != 'python':
487 524
         setattr(SerializerTests, 'test_' + format + '_serializer_stream', curry(streamTest, format))
  525
+

0 notes on commit 20c69c5

Please sign in to comment.
Something went wrong with that request. Please try again.