Closed maxyz closed 1 year ago
Still it won't fix a querystring ?key=string1
-> so it would also need to modify key
to list[str] | str
. Which is, not particularly nice. :/
You can check type of the key. If the required type is the list.
You can check type of the key. If the required type is the list.
Ok, I made a pr (#44) following this idea. I had a couple of minor problems, the main one was that pydantic_dataclass was marking the field as required, so I had to switch to use create_pydantic_model_from_dataclass, which will be no longer exported in pydantic 2.0, so a better solution will be needed (the weird thing is that if I don't add a value to the model then it's tagged as required: false, but if the value is present then it's tagged as required: true, I guess this is due to an optimization in pydantic).
I also added the deps needed to run the tests to the dev dependencies.
Anyway, it's a wip. Please let me know if that's what you had in mind.
I fixed this issue by overriding validate_querystring as the current implementation is well let's use word 'lacking'.
I copied this code: https://github.com/pgjones/quart-schema/blob/main/src/quart_schema/validation.py#L56 Using knowledge from this answer to question: https://stackoverflow.com/questions/75165745/cannot-determine-if-type-of-field-in-a-pydantic-model-is-of-type-list#answer-75166583
Basically, before we pass query arguments to pydantic model, we check if they are lists and if so access it via getlist(key) vs request_args[key], which can be expanded to support tuples, sets, etc.
End result:
from functools import wraps
from typing import Any, Callable
from humps import decamelize
from pydantic import ValidationError
from pydantic.fields import SHAPE_LIST
from pydantic.schema import model_schema
from quart import current_app, request
from quart_schema.typing import Model
from quart_schema.validation import (
QUART_SCHEMA_QUERYSTRING_ATTRIBUTE,
QuerystringValidationError,
SchemaInvalidError,
_to_pydantic_model,
)
def validate_querystring(model_class: Model) -> Callable:
"""Validate the request querystring arguments.
This ensures that the query string arguments can be converted to
the *model_class*. If they cannot a `RequestSchemaValidationError`
is raised which by default results in a 400 response.
Arguments:
model_class: The model to use, either a dataclass, pydantic
dataclass or a class that inherits from pydantic's
BaseModel. All the fields must be optional.
"""
model_class = _to_pydantic_model(model_class)
schema = model_schema(model_class)
if len(schema.get("required", [])) != 0:
raise SchemaInvalidError("Fields must be optional")
def decorator(func: Callable) -> Callable:
setattr(func, QUART_SCHEMA_QUERYSTRING_ATTRIBUTE, model_class)
@wraps(func)
async def wrapper(*args: Any, **kwargs: Any) -> Any:
if current_app.config["QUART_SCHEMA_CONVERT_CASING"]:
request_args = decamelize(request.args)
else:
request_args = request.args
parsed_args = {}
for key in request_args:
if model_class.__fields__[key].shape == SHAPE_LIST:
parsed_args[key] = request_args.getlist(key)
else:
parsed_args[key] = request_args[key]
try:
model = model_class(**parsed_args)
except (TypeError, ValidationError) as error:
raise QuerystringValidationError(error)
else:
return await current_app.ensure_async(func)(*args, query_args=model, **kwargs)
return wrapper
return decorator
I've implemented a solution in c2d20688fc6470429f5f045c8426dee3944fc054.
I would like to use a querystring with a parameter that's a list.
I've done:
Which generates the documentation as expected, but when you try to use it with:
I get
I could workaround this using:
Should that be part of quart-schema? Should it be fixed in the werkzeug directly?