zerocool
zerocool

Reputation: 833

how to keep order of sorted dictionary passed to jsonify() function?

I'm trying to pass sorted dictionary to jsonify() function and then use it from within JS code to take out values. What I see there is that even though I pass correct values, they are reordered by jsonify for some reason.


json_data = {
    "11": {
        "j_id": "out",
    },
    "aa": {
        "j_id": "in",
    },
    "bb": {
        "j_id": "out",
    },
}

jkeys=json_data.keys()
sorted_json = sorted(jkeys, key=lambda x: json_data[x]['j_id'], reverse=False)

new_sorted=OrderedDict()
for rec in sorted_json:
    new_sorted[rec]=json_data[rec]

print('sort dict: {}'.format(new_sorted))

The output is correct and I can see proper values which in my case should be: aa, 11, bb

>>> from collections import OrderedDict
>>>
>>> json_data = {
...     "11": {
...         "j_id": "out",
...     },
...     "aa": {
...         "j_id": "in",
...     },
...     "bb": {
...         "j_id": "out",
...     },
... }
>>>
>>> jkeys=json_data.keys()
>>> sorted_json = sorted(jkeys, key=lambda x: json_data[x]['j_id'], reverse=False)
>>>
>>> new_sorted=OrderedDict()
>>> for rec in sorted_json:
...     new_sorted[rec]=json_data[rec]
...
>>> print('sort dict: {}'.format(new_sorted))
sort dict: OrderedDict([('aa', {'j_id': 'in'}), ('11', {'j_id': 'out'}), ('bb', {'j_id': 'out'})])

Unfortunately, when I pass this to jsonify() function and then for example console.log() output of flask data, the orderd becomes like that: 11, aa, bb. Additionally to that, I've done some research and found this stackoverflow answer, leading to some good documentation notes which clearly states that setting JSON_SORT_KEYS to False is not recommended way. Then I checked this github issue and it seems that problem is not fully resolved in flask.

What would be the best way to fix it in my case?

Upvotes: 52

Views: 28421

Answers (5)

Saeed Ir
Saeed Ir

Reputation: 2332

Add this config line to your code after the app definition:

app = Flask(__name__)
app.config['JSON_SORT_KEYS'] = False

Update: For Flask 2.3 and later use this:

app.json.sort_keys = False

Upvotes: 126

Shayan
Shayan

Reputation: 2471

Please refer to the Flask documentation 2.3.x changes (Released: 2023-04-25)

The JSON_AS_ASCII, JSON_SORT_KEYS, JSONIFY_MIMETYPE, and JSONIFY_PRETTYPRINT_REGULAR config keys are removed.

Version 2.3.x has DefaultJSONProvider class with a default parameter: sort_keys = True

DefaultJSONProvider Class description

To disable default JSON (dict) key sort:

from flask import Flask

app = Flask(__name__)
app.json.sort_keys = False

Upvotes: 4

Seb
Seb

Reputation: 4576

The solution to set app.config['JSON_SORT_KEYS'] = False no longer does the trick in the latest version of Flask (2.3), nor does it in Flask's asyncio-based sibling Quart.

The new way to turn off sorting is to update the sort_keys attribute on the app's JSONProvider instance:

from flask import Flask  # or from quart import Quart, etc.

app = Flask(__name__)
app.json.sort_keys = False

or if you're already using a custom JSONProvider subclass:

from flask import Flask
from flask.json.provider import DefaultJSONProvider

class CustomJSONProvider(DefaultJSONProvider):
    sort_keys = False

app = Flask(__name__)
app.json = CustomJSONProvider(app)

Upvotes: 15

Adjetey Octavius
Adjetey Octavius

Reputation: 51

By default, keys from json are sorted to true. You need to override this in your project config as follows:

app.config['JSON_SORT_KEYS'] = False

Upvotes: 4

Martijn Pieters
Martijn Pieters

Reputation: 1121684

JSON objects are unordered structures, and your browser could easily end up discarding the order of your JSON keys again.

From the JSON standard:

An object is an unordered set of name/value pairs.

Bold emphasis mine. To remain standards compliant, use a list (JSON array) to capture a specific order.

That said, Flask can be made to preserve the order you set with OrderedDict.

  • Disable sorting app-wide, with JSON_SORT_KEYS = False.

    With this setting at the default True, jsonify() sorts keys to provide stable HTTP responses that are cacheable. The documentation warns against disabling this only to make you aware of the downside of setting this to False.

    However, if you are using Python 3.6 or newer this concern doesn't actually play because as of that version the built-in dict type also preserves insertion order, and so there is no problem with the order changing from one Python run to the next.

  • Instead of using jsonify(), use flask.json.dumps() directly, and create your own Response object. Pass in sort_keys=False:

    from flask import json
    
    response = current_app.response_class(
        json.dumps(new_sorted, sort_keys=False),
        mimetype=current_app.config['JSONIFY_MIMETYPE'])
    

Upvotes: 18

Related Questions