Opened 19 years ago

Closed 19 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 19 years ago.
Sample

Download all attachments as: .zip

Change History (5)

by tangerine, 19 years ago

Attachment: serialization_example.py​ added

Sample

comment:1 by Gary Wilson, 19 years ago

Triage Stage: Unreviewed → Design 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, 19 years ago

Triage Stage: Design decision needed → Accepted

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, 19 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, 19 years ago

Resolution: → fixed
Status: new → closed

(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