luolingchun / flask-openapi3

Generate REST API and OpenAPI documentation for your Flask project.
https://luolingchun.github.io/flask-openapi3/
MIT License
204 stars 33 forks source link

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

Closed aodj-kara closed 2 months ago

aodj-kara commented 4 months ago

Environment:

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)
luolingchun commented 3 months ago

@aodj-kara Thanks for the report, I've submitted a PR(#167) to fix it.