flask-openapi3 icon indicating copy to clipboard operation
flask-openapi3 copied to clipboard

`populate_by_name` doesn't work for `query` instances

Open aodj-kara opened this issue 7 months ago • 1 comments

Environment:

  • Python version: 3.11.9
  • Flask version: 2.3.3
  • flask-openapi3 version: 3.1.2

When using the query: ... object in a route, if the Pydantic class used, has populate_by_name=True set in the model configuration, the _validate_query method doesn't make use of it.

from typing import Optional, Type, Union

from pydantic import BaseModel, ConfigDict
from pydantic.alias_generators import to_camel
from werkzeug.datastructures import ImmutableMultiDict

args = ImmutableMultiDict([("user_id", 1)])


class Users(BaseModel):
    user_id: int

    model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)


def validate_query(query: Type[BaseModel], request_args):
    query_dict = {}
    for k, v in query.model_json_schema().get("properties", {}).items():
        value: Union[list, Optional[str]]
        if v.get("type") == "array":
            value = request_args.getlist(k)
        else:
            value = request_args.get(k)
        if value is not None:
            query_dict[k] = value
    return query_dict

The above example uses a slightly modified version of the _validate_query method in request.py to determine how the internals parse the Pydantic query class.

It looks like the reliance upon the .model_json_schema() output means that (in reference to the example) the query must use userId and can not use user_id in the request. Setting the populate_by_name flag has no affect on the parsing, even though in normal Pydantic use, this would allow the user to populate the User object by either user_id or userId.

>>> Users(user_id=1)
Users(user_id=1)
>>> Users(userId=1)
Users(user_id=1)

aodj-kara avatar Jul 24 '24 14:07 aodj-kara