Skip to content

Conversation

@KalleDK
Copy link
Contributor

@KalleDK KalleDK commented Nov 14, 2025

This is used when objects like IPv4Address or other custom objects is not reconised by the json serializer.

Often you want your model_dump to give you the object not serialized like IPv4Addresses, but you want model_dump(mode="json") to give you the string.

I would even suggest that mode="json" should be default, but I'm afraid that would break som peoples code.

from ipaddress import IPv4Address
import pydantic

class Demo(pydantic.BaseModel):
    ip: IPv4Address


d = Demo(ip=IPv4Address("127.0.0.1"))
d.model_dump()
# {'ip': IPv4Address('127.0.0.1')}
d.model_dump(mode="json")
# {'ip': '127.0.0.1'}

This is used when objects like IPv4Address or other custom objects is not reconised by the json serializer.
@pgjones
Copy link
Owner

pgjones commented Dec 2, 2025

I'm not sure this is required, the addition of a JSONEncoder here should ensure that it is converted to JSON

@KalleDK
Copy link
Contributor Author

KalleDK commented Dec 3, 2025

I can only have this working when I set mode

Without mode

from http import HTTPStatus
from ipaddress import IPv4Address

import pydantic
import quart_schema
from quart import Quart


class DemoResp(pydantic.BaseModel):
    message: str
    ip: IPv4Address


schema = quart_schema.QuartSchema()
app = Quart(__name__)
schema.init_app(app)


@app.get("/hello")
@quart_schema.validate_response(DemoResp, HTTPStatus.OK)
def hello() -> tuple[DemoResp, int]:
    return DemoResp(message="Hello, World!", ip=IPv4Address("127.0.0.1")), HTTPStatus.OK


if __name__ == "__main__":
    app.run(host="127.0.0.1", port=5000)
pydantic_core._pydantic_core.PydanticSerializationError: Unable to serialize unknown type: <class 'ipaddress.IPv4Address'>
[2025-12-03 09:37:49 +0100] [39524] [INFO] 127.0.0.1:60923 GET /hello 1.1 500 265 67192

With mode

from http import HTTPStatus
from ipaddress import IPv4Address

import pydantic
import quart_schema
from quart import Quart


class DemoResp(pydantic.BaseModel):
    message: str
    ip: IPv4Address


schema = quart_schema.QuartSchema()
app = Quart(__name__)
app.config["QUART_SCHEMA_PYDANTIC_DUMP_OPTIONS"] = {"mode": "json"}
schema.init_app(app)


@app.get("/hello")
@quart_schema.validate_response(DemoResp, HTTPStatus.OK)
def hello() -> tuple[DemoResp, int]:
    return DemoResp(message="Hello, World!", ip=IPv4Address("127.0.0.1")), HTTPStatus.OK


if __name__ == "__main__":
    app.run(host="127.0.0.1", port=5000)
[2025-12-03 09:39:29 +0100] [12112] [INFO] Running on http://127.0.0.1:5000 (CTRL + C to quit)
[2025-12-03 09:39:54 +0100] [12112] [INFO] 127.0.0.1:55864 GET /hello 1.1 200 45 8726

@KalleDK
Copy link
Contributor Author

KalleDK commented Dec 3, 2025

@pgjones
And an example of some models that handles what I call stupid api xD

from http import HTTPStatus

import pydantic
import quart_schema
from quart import Quart


class StupidApiModel(pydantic.BaseModel):
    name: str
    version: str

    @pydantic.field_validator("version", "name", mode="before")
    @classmethod
    def _validate_value_dict(cls, v: dict[str, str] | str) -> str:
        if isinstance(v, str):
            return v
        return v["value"]

    @pydantic.field_serializer("version", "name", when_used="json")
    def _serialize_value_dict(self, v: str) -> dict[str, str]:
        return {"value": v}


schema = quart_schema.QuartSchema()
app = Quart(__name__)
schema.init_app(app)


@app.get("/world")
@quart_schema.validate_response(StupidApiModel, HTTPStatus.OK)
def world() -> tuple[StupidApiModel, int]:
    return StupidApiModel(name="World", version="1.0"), HTTPStatus.OK


if __name__ == "__main__":
    app.run(host="127.0.0.1", port=5000)

This incorrectly returns {"name":"World","version":"1.0"}

With the json mode

from http import HTTPStatus

import pydantic
import quart_schema
from quart import Quart


class StupidApiModel(pydantic.BaseModel):
    name: str
    version: str

    @pydantic.field_validator("version", "name", mode="before")
    @classmethod
    def _validate_value_dict(cls, v: dict[str, str] | str) -> str:
        if isinstance(v, str):
            return v
        return v["value"]

    @pydantic.field_serializer("version", "name", when_used="json")
    def _serialize_value_dict(self, v: str) -> dict[str, str]:
        return {"value": v}


schema = quart_schema.QuartSchema()
app = Quart(__name__)
app.config["QUART_SCHEMA_PYDANTIC_DUMP_OPTIONS"] = {"mode": "json"}
schema.init_app(app)


@app.get("/world")
@quart_schema.validate_response(StupidApiModel, HTTPStatus.OK)
def world() -> tuple[StupidApiModel, int]:
    return StupidApiModel(name="World", version="1.0"), HTTPStatus.OK


if __name__ == "__main__":
    app.run(host="127.0.0.1", port=5000)

Correctly returns {"name":{"value":"World"},"version":{"value":"1.0"}}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants