Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask JSON serializable error because of flask babel

I am using https://pythonhosted.org/Flask-Babel/ extention for localization.

base form class

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from app import app
from flask.ext.wtf import Form

class BaseForm(Form):

    @property
    def error_list(self):
        _errors = []

        for fieldName, errorMessages in self.errors.iteritems():
            for err in errorMessages:
                _errors.append(err)

        return _errors

my form class

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from flask import g

from wtforms import StringField, TextField, PasswordField # BooleanField
import wtforms.validators as validators
from flask.ext.babel import lazy_gettext as _
from flask.ext.babel import npgettext as _n

from app.base_forms import *

class PostForm(BaseForm):
    post_title    = StringField(_("Post Title"), [validators.Required(message=_("Post title is required")) ])
    post_content = StringField(_("Post Content"), [ validators.Required(message=_("Post content is required"))])

my view

...
viewJsonData["error_list"] = form.error_list
return jsonify(**viewJsonData)

It throws this error "TypeError: lu'Post content is required' is not JSON serializable".

when i remove localization from _("Post Title") to "Post Title" it work but when i use babel it does not work

I think it is about unicode. because i did this change _("Post Title").encode("utf-8") it works. But this solution is not effective. How can i solve the problem.

like image 992
Alexander Avatar asked Sep 30 '14 15:09

Alexander


1 Answers

The issue is that your error message is a _LazyString object returned by lazy_gettext, not a string. Normally, this wouldn't be an issue because displaying it in a template would call str() on it, causing it to evaluate the translation. However, you are collecting the objects in error_list, and then passing them to jsonify, and json has no serializer for these objects.

You need to tell Flask's JSON serializer how to handle these objects. Write a custom serializer then assign it to app.json_encoder.

from flask._compat import text_type
from flask.json import JSONEncoder as BaseEncoder
from speaklater import _LazyString

class JSONEncoder(BaseEncoder):
    def default(self, o):
        if isinstance(o, _LazyString):
            return text_type(o)

        return BaseEncoder.default(self, o)

app.json_encoder = JSONEncoder
like image 131
davidism Avatar answered Oct 10 '22 04:10

davidism