Search code examples
pythonjsonpydantic

Is it possible to get pydantic v2 to dump json with sorted keys?


In the pydantic v1 there was an option to add kwargs which would get passed to json.dumps via **dumps_kwargs. However, in pydantic v2 if you try to add extra kwargs to BaseModel.json() it fails with the error TypeError: `dumps_kwargs` keyword arguments are no longer supported.

Here is example code with a workaround using dict()/model_dump(). This is good enough as long as the types are simple, but it won't work for the more complex data types that pydantic knows how to serialize.

Is there a way to get sort_keys to work in pydantic v2 in general?

import json
from pydantic import BaseModel


class JsonTest(BaseModel):
    b_field: int
    a_field: str

obj = JsonTest(b_field=1, a_field="one")

# this worked in pydantic v1 but raises a TypeError in v2
# print(obj.json(sort_keys=True)

print(obj.model_dump_json())
# {"b_field":1,"a_field":"one"}

# workaround for simple objects
print(json.dumps(obj.model_dump(), sort_keys=True))
# {"a_field": "one", "b_field": 1}

Solution

  • I'm not sure whether it is an elegant solution but you could leverage the fact that dictionaries (since python 3.7) preserve an order of elements:

    from typing import Any, Dict
    from pydantic import BaseModel, model_serializer
    
    
    class JsonTest(BaseModel):
        b_field: int
        c_field: int
        a_field: str
    
        @model_serializer(when_used='json')
        def sort_model(self) -> Dict[str, Any]:
            return dict(sorted(self.model_dump().items()))
    
    
    obj = JsonTest(b_field=1, a_field="one", c_field=0)
    print(obj.model_dump_json())
    # {"a_field":"one","b_field":1,"c_field":0}