【问题标题】:Proper overloading of json encoding and decoding with Flask使用 Flask 正确重载 json 编码和解码
【发布时间】:2015-04-17 03:40:21
【问题描述】:

我正在尝试向 Flask JSON 编码器/解码器添加一些重载以添加日期时间编码/解码,但仅通过“hack”成功。

from flask import Flask, flash, url_for, redirect, render_template_string
from flask.json import JSONEncoder, JSONDecoder


template = """
<!DOCTYPE html>
<html><head><title>Test JSON encoder/decoder</title></head><body>
{% with messages = get_flashed_messages(with_categories=true) %}{% if messages %}{% for message in messages %}
<p>Flash: {{ message }}</p>
{% endfor %}{% endif %}{% endwith %}
<p>Flash should be: ['Flash message', 'success']</p>
<p><a href="{{ url_for('index') }}">Try again</a></p>
</body></html>
"""


class CustomJSONEncoder(JSONEncoder):
    """ Do nothing custom json encoder """
    def default(self, obj):
        # My custom logic here
        # ...
        # or
        return super(CustomJSONEncoder, self).defaults(obj)


class CustomJSONDecoder(JSONDecoder):
    """ Do nothing custom json decoder """
    def __init__(self, *args, **kargs):
        _ = kargs.pop('object_hook', None)
        super(CustomJSONDecoder, self).__init__(object_hook=self.decoder, *args, **kargs)

    def decoder(self, d):
        # My custom logic here
        # ...
        # or
        return d


app = Flask(__name__, static_url_path='')
app.config['SECRET_KEY'] = 'secret-key'
app.json_encoder = CustomJSONEncoder
app.json_decoder = CustomJSONDecoder


@app.route('/')
def index():
    flash('Flash message', 'success')
    return redirect(url_for('display'))


@app.route('/b')
def display():
    return render_template_string(template)


if __name__ == '__main__':
    app.run(debug=True, port=5200)

我应该像这样从 Flask.sessions.TaggedJSONSerializer 复制一些代码:

import uuid
from base64 import b64decode
from werkzeug.http import parse_date
from markupsafe import Markup
from flask._compat import iteritems


class CustomJSONDecoder(JSONDecoder):
    """ Do nothing custom json decoder """
    def __init__(self, *args, **kargs):
        _ = kargs.pop('object_hook', None)
        super(CustomJSONDecoder, self).__init__(object_hook=self.decoder, *args, **kargs)

    def decode(self, d):
        # My custom logic here
        # ...
        # Copy of the code from Flask.sessions.TaggedJSONSerializer(object).loads(self, value).object_hook(obj)
        if len(d) == 1:
            the_key, the_value = next(iteritems(d))
            if the_key == ' t':
                return tuple(the_value)
            elif the_key == ' u':
                return uuid.UUID(the_value)
            elif the_key == ' b':
                return b64decode(the_value)
            elif the_key == ' m':
                return Markup(the_value)
            elif the_key == ' d':
                return parse_date(the_value)
        return d

我做得“正确”还是有什么我想念的?

【问题讨论】:

    标签: python json session flask decoding


    【解决方案1】:

    您可以通过显式调用它的 default() 方法来使用基类的功能。我已经在我的自定义 JSONEncoder 中成功地做到了:

    class CustomJSONEncoder(JSONEncoder):
        def default(self, obj):
            # Calling custom encode function:
            jsonString = HelperFunctions.jsonEncodeHandler(obj)
            if (jsonString != obj):  # Encode function has done something
                return jsonString  # Return that
            return JSONEncoder.default(self, obj)  # else let the base class do the work
    

    但是,在解码器中,您应该记住传递给__init__() 函数的对象挂钩并从您自己的挂钩中调用它:

    class CustomJSONDecoder(JSONDecoder):
        def __init__(self, *args, **kwargs):
            self.orig_obj_hook = kwargs.pop("object_hook", None)
            super(CustomJSONDecoder, self).__init__(*args,
                object_hook=self.custom_obj_hook, **kwargs)
    
        def custom_obj_hook(self, dct):
            # Calling custom decode function:
            dct = HelperFunctions.jsonDecodeHandler(dct)
            if (self.orig_obj_hook):  # Do we have another hook to call?
                return self.orig_obj_hook(dct)  # Yes: then do it
            return dct  # No: just return the decoded dict
    

    顺便说一句:您的解码器中有错字:您在基类中注册的对象挂钩名为self.decoder,但成员定义为def decode(...)(没有r结尾)。在您的示例中,您注册了一个空钩子,并且永远不应调用 decode()

    【讨论】:

      【解决方案2】:

      请注意,您必须告诉您的烧瓶应用程序它将使用什么编码器:

      app.json_encoder = CustomJSONEncoder
      

      这解决了我的问题。

      【讨论】:

        猜你喜欢
        • 2013-09-21
        • 2016-07-18
        • 1970-01-01
        • 1970-01-01
        • 2016-04-04
        • 1970-01-01
        • 1970-01-01
        • 2013-07-12
        • 1970-01-01
        相关资源
        最近更新 更多