Commit 960d3172 authored by Russell Keith-Magee's avatar Russell Keith-Magee
Browse files

[1.0.X] Fixed #9522 -- Modified handling of values in base serializer so that...

[1.0.X] Fixed #9522 -- Modified handling of values in base serializer so that field subclasses can define their own value_to_string() method for serialization. Thanks to Alex Koshelev for the report and initial patch.

Merge of r10554 from trunk.


git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@10555 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 6be2d903
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@ other serializers.
from django.conf import settings
from django.core.serializers import base
from django.db import models
from django.utils.encoding import smart_unicode
from django.utils.encoding import smart_unicode, is_protected_type

class Serializer(base.Serializer):
    """
@@ -35,7 +35,14 @@ class Serializer(base.Serializer):
        self._current = None

    def handle_field(self, obj, field):
        self._current[field.name] = smart_unicode(getattr(obj, field.name), strings_only=True)
        value = field._get_val_from_obj(obj)
        # Protected types (i.e., primitives like None, numbers, dates,
        # and Decimals) are passed through as is. All other values are
        # converted to string first.
        if is_protected_type(value):
            self._current[field.name] = value
        else:
            self._current[field.name] = field.value_to_string(obj)

    def handle_fk_field(self, obj, field):
        related = getattr(obj, field.name)
+2 −4
Original line number Diff line number Diff line
@@ -65,11 +65,9 @@ class Serializer(base.Serializer):
            "type" : field.get_internal_type()
        })

        # Get a "string version" of the object's data (this is handled by the
        # serializer base class).
        # Get a "string version" of the object's data.
        if getattr(obj, field.name) is not None:
            value = self.get_string_value(obj, field)
            self.xml.characters(smart_unicode(value))
            self.xml.characters(field.value_to_string(obj))
        else:
            self.xml.addQuickElement("None")

+14 −1
Original line number Diff line number Diff line
@@ -41,6 +41,19 @@ def smart_unicode(s, encoding='utf-8', strings_only=False, errors='strict'):
        return s
    return force_unicode(s, encoding, strings_only, errors)

def is_protected_type(obj):
    """Determine if the object instance is of a protected type.

    Objects of protected types are preserved as-is when passed to
    force_unicode(strings_only=True).
    """
    return isinstance(obj, (
        types.NoneType,
        int, long,
        datetime.datetime, datetime.date, datetime.time,
        float, Decimal)
    )

def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'):
    """
    Similar to smart_unicode, except that lazy instances are resolved to
@@ -48,7 +61,7 @@ def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'):

    If strings_only is True, don't convert (some) non-string-like objects.
    """
    if strings_only and isinstance(s, (types.NoneType, int, long, datetime.datetime, datetime.date, datetime.time, float, Decimal)):
    if strings_only and is_protected_type(s):
        return s
    try:
        if not isinstance(s, basestring,):
+68 −0
Original line number Diff line number Diff line
@@ -73,6 +73,45 @@ class Movie(models.Model):
class Score(models.Model):
    score = models.FloatField()


class Team(object):
    def __init__(self, title):
        self.title = title

    def __unicode__(self):
        raise NotImplementedError("Not so simple")

    def __str__(self):
        raise NotImplementedError("Not so simple")

    def to_string(self):
        return "%s" % self.title

class TeamField(models.CharField):
    __metaclass__ = models.SubfieldBase

    def __init__(self):
        super(TeamField, self).__init__(max_length=100)

    def get_db_prep_save(self, value):
        return unicode(value.title)

    def to_python(self, value):
        if isinstance(value, Team):
            return value
        return Team(value)

    def value_to_string(self, obj):
        return self._get_val_from_obj(obj).to_string()

class Player(models.Model):
    name = models.CharField(max_length=50)
    rank = models.IntegerField()
    team = TeamField()

    def __unicode__(self):
        return u'%s (%d) playing for %s' % (self.name, self.rank, self.team.to_string())

__test__ = {'API_TESTS':"""
# Create some data:
>>> from datetime import datetime
@@ -223,6 +262,21 @@ None
>>> print list(serializers.deserialize('json', serializers.serialize('json', [sc])))[0].object.score
3.4

# Custom field with non trivial to string convertion value
>>> player = Player()
>>> player.name = "Soslan Djanaev"
>>> player.rank = 1
>>> player.team = Team("Spartak Moskva")
>>> player.save()

>>> serialized = serializers.serialize("json", Player.objects.all())
>>> print serialized
[{"pk": 1, "model": "serializers.player", "fields": {"name": "Soslan Djanaev", "rank": 1, "team": "Spartak Moskva"}}]

>>> obj = list(serializers.deserialize("json", serialized))[0]
>>> print obj
<DeserializedObject: Soslan Djanaev (1) playing for Spartak Moskva>

"""}

try:
@@ -259,6 +313,20 @@ try:
<DeserializedObject: Just kidding; I love TV poker>
<DeserializedObject: Time to reform copyright>

# Custom field with non trivial to string convertion value with YAML serializer

>>> print serializers.serialize("yaml", Player.objects.all())
- fields: {name: Soslan Djanaev, rank: 1, team: Spartak Moskva}
  model: serializers.player
  pk: 1
<BLANKLINE>

>>> serialized = serializers.serialize("yaml", Player.objects.all())
>>> obj = list(serializers.deserialize("yaml", serialized))[0]
>>> print obj
<DeserializedObject: Soslan Djanaev (1) playing for Spartak Moskva>


"""
except ImportError:
    pass