Commit 20c69c5e authored by Karen Tracey's avatar Karen Tracey
Browse files

Fix #17879: Corrected regression in python (inherited by yaml and json)...

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
parent 2f520139
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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>
+4 −1
Original line number Diff line number Diff line
@@ -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)
            if related:
                value = related.natural_key()
            else:
                value = None
        else:
            value = getattr(obj, field.get_attname())
        self._current[field.name] = value
+16 −0
Original line number Diff line number Diff line
@@ -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
+39 −1
Original line number Diff line number Diff line
@@ -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))