Proper overloading of json encoding and decoding with Flask

2024/9/20 18:51:21

I am trying to add some overloading to the Flask JSON encoder/decoder to add datetime encoding/decoding but only succeeded through a 'hack'.

from flask import Flask, flash, url_for, redirect, render_template_string
from flask.json import JSONEncoder, JSONDecodertemplate = """
<!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# ...# orreturn 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# ...# orreturn dapp = 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)

The hack is that I should copy some code from the Flask.sessions.TaggedJSONSerializer like that:

import uuid
from base64 import b64decode
from werkzeug.http import parse_date
from markupsafe import Markup
from flask._compat import iteritemsclass 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

Do I do it 'correctly' or there is something that I miss?

Answer

You can use the functionality of the base class by explicitly calling it's default() method. I have done that in my custom JSONEncoder successfully:

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

In the decoder, however, you should remember the object hook passed to the __init__() function and call it from your own hook:

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 itreturn dct  # No: just return the decoded dict

BTW: You have a typo in your decoder: the object hook you register in the base class is named self.decoder, but the member is defined as def decode(...) (without the r at the end). In your example, you register an empty hook and the decode() should never get called.

https://en.xdnf.cn/q/72141.html

Related Q&A

How to check a specific type of tuple or list?

Suppose, var = (x, 3)How to check if a variable is a tuple with only two elements, first being a type str and the other a type int in python? Can we do this using only one check? I want to avoid this…

Cannot import name BlockBlobService

I got the following error:from azure.storage.blob import BlockBlobService ImportError: cannot import name BlockBlobServicewhen trying to run my python project using command prompt. (The code seems to…

Legend outside the plot in Python - matplotlib

Im trying to place a rather extensive legend outside my plot in matplotlib. The legend has quite a few entries, and each entry can be quite long (but I dont know exactly how long).Obviously, thats quit…

Filter items that only occurs once in a very large list

I have a large list(over 1,000,000 items), which contains english words:tokens = ["today", "good", "computer", "people", "good", ... ]Id like to get al…

Get Data JSON in Flask

Even following many example here & there, i cant get my API work in POST Method. Here the code about it :from flask import Flask, jsonify, request@app.route(/api/v1/lists, methods=[POST]) def add_e…

Commands working on windows command line but not in Git Bash terminal

I am trying to run certain commands in Git Bash but they continue to hang and not display anything. When I run them in the Windows command prompt they work.For example, in my windows command prompt the…

RBF interpolation: LinAlgError: singular matrix

The following call:rbf = Rbf(points[0], points[1], values,epsilon=2)results in an error:LinAlgError: singular matrixwith the following values:In [3]: points Out[3]: (array([71, 50, 48, 84, 71, 74, 89,…

What does `\x1b(B` do?

Im a Blessed user, and recently, when I tried to find out the contents of the term.bold() function, I got this output: \x1b[1m\x1b(B\x1b[mI understand what \x1b[1m and \x1b[m do, but what does \x1b(B d…

Not clicking all tabs and not looping once issues

I am trying to click the tabs on the webpage as seen below. Unfortunately, it only seems to click some of the tabs despite correct correct xpath in inspect Chrome. I can only assume it’s not clickin…

Opencv stream from a camera connected to a remote machine

I am developing a wx application in python for streaming and displaying video from two different webcams. This works fine, but now I need to do this in a different scenario in which the two cameras are…