Ticket #17587: fk_serialize.patch

File fk_serialize.patch, 5.4 KB (added by aburgel, 3 years ago)
  • django/core/serializers/python.py

    diff --git a/django/core/serializers/python.py b/django/core/serializers/python.py
    index a68ea21..57a34de 100644
    a b class Serializer(base.Serializer): 
    5050            if self.use_natural_keys and hasattr(related, 'natural_key'):
    5151                related = related.natural_key()
    5252            else:
    53                 if field.rel.field_name == related._meta.pk.name:
    54                     # Related to remote object via primary key
    55                     related = related._get_pk_val()
    56                 else:
    57                     # Related to remote object via other field
    58                     related = smart_unicode(getattr(related, field.rel.field_name), strings_only=True)
     53                related_field = field.rel.get_related_field()
     54                related = related_field.value_to_string(related)
    5955        self._current[field.name] = related
    6056
    6157    def handle_m2m_field(self, obj, field):
  • django/core/serializers/xml_serializer.py

    diff --git a/django/core/serializers/xml_serializer.py b/django/core/serializers/xml_serializer.py
    index bcf5631..373dc59 100644
    a b class Serializer(base.Serializer): 
    9696                    self.xml.characters(smart_unicode(key_value))
    9797                    self.xml.endElement("natural")
    9898            else:
    99                 if field.rel.field_name == related._meta.pk.name:
    100                     # Related to remote object via primary key
    101                     related = related._get_pk_val()
    102                 else:
    103                     # Related to remote object via other field
    104                     related = getattr(related, field.rel.field_name)
     99                related_field = field.rel.get_related_field()
     100                related = related_field.value_to_string(related)
    105101                self.xml.characters(smart_unicode(related))
    106102        else:
    107103            self.xml.addQuickElement("None")
  • tests/modeltests/serializers/models.py

    diff --git a/tests/modeltests/serializers/models.py b/tests/modeltests/serializers/models.py
    index 9948afd..6655c31 100644
    a b class Player(models.Model): 
    117117
    118118    def __unicode__(self):
    119119        return u'%s (%d) playing for %s' % (self.name, self.rank, self.team.to_string())
     120
     121
     122class ProductCode(object):
     123    def __init__(self, code):
     124        self.code = code
     125
     126    def __unicode__(self):
     127        raise NotImplementedError("Not so simple")
     128
     129    def __str__(self):
     130        raise NotImplementedError("Not so simple")
     131
     132    def to_string(self):
     133        return u'%s' % self.code
     134
     135
     136class ProductCodeField(models.CharField):
     137    __metaclass__ = models.SubfieldBase
     138
     139    def __init__(self):
     140        super(ProductCodeField, self).__init__(max_length=100, unique=True)
     141
     142    def get_prep_value(self, value):
     143        if isinstance(value, ProductCode):
     144            return unicode(value.code)
     145        return value
     146
     147    def get_db_prep_save(self, value, connection):
     148        return unicode(value.code)
     149
     150    def to_python(self, value):
     151        if isinstance(value, ProductCode):
     152            return value
     153        return ProductCode(value)
     154
     155    def value_to_string(self, obj):
     156        return self._get_val_from_obj(obj).to_string()
     157
     158
     159class Product(models.Model):
     160    code = ProductCodeField()
     161
     162    def __unicode__(self):
     163        return u'product %s' % self.code.to_string()
     164
     165
     166class Order(models.Model):
     167    product = models.ForeignKey(Product, to_field='code')
     168    amount = models.IntegerField()
     169
     170    def __unicode__(self):
     171        return u'order for %d items of %s' % (self.amount, self.product)
  • tests/modeltests/serializers/tests.py

    diff --git a/tests/modeltests/serializers/tests.py b/tests/modeltests/serializers/tests.py
    index 721ca09..ec8d4f5 100644
    a b from django.test import TestCase, TransactionTestCase, Approximate 
    1414from django.utils import simplejson, unittest
    1515
    1616from .models import (Category, Author, Article, AuthorProfile, Actor, Movie,
    17     Score, Player, Team)
     17    Score, Player, Team, Product, Order)
    1818
    1919
    2020class SerializerRegistrationTests(unittest.TestCase):
    class SerializersTestBase(object): 
    219219        self.assertEqual(deserial_objs[0].object.team.to_string(),
    220220                         player.team.to_string())
    221221
     222    def test_custom_field_foreign_key_serialization(self):
     223        """Tests that custom fields as foreign keys serialize and deserialize intact"""
     224        code_str = "AB1234"
     225        product = Product()
     226        product.code = code_str
     227        product.save()
     228
     229        order = Order()
     230        order.product = product
     231        order.amount = 10
     232        order.save()
     233
     234        serial_str = serializers.serialize(self.serializer_name,
     235                                           Order.objects.all())
     236        product = self._get_field_values(serial_str, "product")
     237        self.assertTrue(product)
     238        self.assertEqual(product[0], code_str)
     239
     240        deserial_objs = list(serializers.deserialize(self.serializer_name, serial_str))
     241        self.assertEqual(deserial_objs[0].object.product.code.to_string(),
     242                         order.product.code.to_string())
     243
    222244    def test_pre_1000ad_date(self):
    223245        """Tests that year values before 1000AD are properly formatted"""
    224246        # Regression for #12524 -- dates before 1000AD get prefixed
Back to Top