Opened 17 years ago

Closed 17 years ago

#5868 closed (fixed)

Newforms ErrorDict serialization problem

Reported by: tangerine Owned by: nobody
Component: Forms Version: dev
Severity: Keywords: serialization newforms JSON
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Around r6625 a bug has been introduced whereby an attempt to serialize a ErrorDict instance will fail and throw a TypeError, complaining of not being able to serialize a proxy object e.g. something like django.utils.functional.__proxy__ object at 0xdeecd0> is not JSON serializable . I have attached some sample code to illustrate the problem.

Attachments (1)

serialization_example.py (408 bytes ) - added by tangerine 17 years ago.
Sample

Download all attachments as: .zip

Change History (5)

by tangerine, 17 years ago

Attachment: serialization_example.py added

Sample

comment:1 by Gary Wilson, 17 years ago

Triage Stage: UnreviewedDesign decision needed

Yes, r6625 turned all newforms error messages into lazy strings, which aren't supported by the default JSONEncoder:

>>> from django.utils import simplejson
>>> simplejson.dumps(ugettext_lazy('hello world'))
Traceback (most recent call last):
  File "<console>", line 1, in ?
  File "/home/gdub/bzr/django/upstream/django/utils/simplejson/__init__.py", line 181, in dumps
    separators=separators,
  File "/home/gdub/bzr/django/upstream/django/utils/simplejson/encoder.py", line 312, in encode
    chunks = list(self.iterencode(o))
  File "/home/gdub/bzr/django/upstream/django/utils/simplejson/encoder.py", line 273, in _iterencode
    for chunk in self._iterencode_default(o, markers):
  File "/home/gdub/bzr/django/upstream/django/utils/simplejson/encoder.py", line 279, in _iterencode_default
    newobj = self.default(o)
  File "/home/gdub/bzr/django/upstream/django/utils/simplejson/encoder.py", line 300, in default
    raise TypeError("%r is not JSON serializable" % (o,))
TypeError: <django.utils.functional.__proxy__ object at 0x892378c> is not JSON serializable

The JSONEncoder docstring states:

    To extend this to recognize other objects, subclass and implement a
    ``.default()`` method with another method that returns a serializable
    object for ``o`` if possible, otherwise it should call the superclass
    implementation (to raise ``TypeError``).

Looks like we might want to do this since lazy strings are used in several places throughout Django. Here's a quick and dirty one that works:

from django.utils.functional import Promise
from django.utils.translation import force_unicode
from django.utils.simplejson import JSONEncoder

class LazyEncoder(JSONEncoder):
    def default(self, o):
        if isinstance(o, Promise):
            return force_unicode(o)
        else:
            return super(LazyEncoder, self).default(o)
>>> simplejson.dumps(ugettext_lazy('hello world'), cls=LazyEncoder)
'"hello world"'
>>> simplejson.dumps([1, 2, ugettext_lazy('hi')], cls=LazyEncoder)
'[1, 2, "hi"]'

comment:2 by Malcolm Tredinnick, 17 years ago

Triage Stage: Design decision neededAccepted

We shouldn't add this code by default, since it's usually going to be unnecessary overhead. It somebody's going to use simplejson directly, they will need to write such a class if there's a chance they are dumping lazy translation objects. I'll update the docs.

I will add something to Django's core serializers to handle the analogous case over there, though.

comment:3 by Malcolm Tredinnick, 17 years ago

Hmm .. on second thoughts, I can't see how we'd ever end up sending a lazy translation object to Django's serializers, so it's not necessary there.

comment:4 by Malcolm Tredinnick, 17 years ago

Resolution: fixed
Status: newclosed

(In [6645]) Fixed #5868 -- Provided an example of how to extend simplejson to serialize
lazy translation objects for those who want to use it directly.

Note: See TracTickets for help on using tickets.
Back to Top