Code

Ticket #17587: fk_serialize.patch

File fk_serialize.patch, 5.4 KB (added by aburgel, 2 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