Open microHoffman opened 4 months ago
Did you find any solution for this @microHoffman?
cc: @tfranzel if you can help please
Found a workaround for it, we can declare a new model using the pydantic.RootModel
:
class MyModel(RootModel):
root: List[MyModel]
and use it with extend_schema
as:
@extend_schema(
request=OpenApiRequest(request=MyModels),
...
)
Found a workaround for it, we can declare a new model using the
pydantic.RootModel
:class MyModel(RootModel): root: List[MyModel]
and use it with
extend_schema
as:@extend_schema( request=OpenApiRequest(request=MyModels), ... )
Thanks a lot for sharing your solution!:)
sry for not replying earlier. I actually looked into this @microHoffman, but was unsure whether we can anything about it.
Basically there is some functionality gap between real serializers and the pydantic plugin. Since list handling is kind of special in DRF, there is not really a easy way of integrating List[MyModel]
without some hefty refactoring. For TypeAdapter
I hit some other issue I was not able to solve with the amount of time I had.
I'm glad that the RootModel this is a viable workaround even if it is not the prettiest. thx @ignis-tech-solutions
@ignis-tech-solutions the key part is the RootModel here. The OpenApiRequest
wrapping should not be necessary.
For anyone running into the same problem, we have managed to add this functionality by using a wrapper class together with a custom extension.
The idea behind this solution is:
contrib.PydanticExtension
extension){ModelName}List
referencing the base modelclass DataclassList:
def __init__(self, model: type[BaseModel]):
self.model = model
class PydanticListExtension(OpenApiSerializerExtension):
target_class = "path.to.DataclassList"
def get_name(self, auto_schema, direction) -> str:
return f"{self.target.model.__name__}List"
def map_serializer(self, auto_schema: AutoSchema, direction: Direction) -> _SchemaType:
# Register schema for component
schema = model_json_schema(self.target.model, ref_template="#/components/schemas/{model}", mode="serialization")
# pull out potential sub-schemas and put them into component section
for sub_name, sub_schema in schema.pop("$defs", {}).items():
component = ResolvedComponent(
name=sub_name,
type=ResolvedComponent.SCHEMA,
object=sub_name,
schema=sub_schema,
)
auto_schema.registry.register_on_missing(component)
# Register the target component directly
component = ResolvedComponent(
name=self.target.model.__name__,
type=ResolvedComponent.SCHEMA,
object=self.target.model.__name__,
schema=schema
)
auto_schema.registry.register_on_missing(component)
result = {
"type": "array",
"items": auto_schema.registry[component.key].ref
}
return result
Note: Fix the import path at the target_class
field in the PydanticListExtension
.
This wrapper is used as follows:
@extend_schema(request=DataclassList(MyDataClass))
def some_action(self, request, *args, **kwargs):
...
@tfranzel Do you think this is worthy adding to the package (perhaps as a blueprint), given it is support for a very specific use-case? If so, I will be be hapy to open a PR integrating and testing these changes.
Hello! I have pydantic v2 model and I'd like to annotate my view using
@extend_schema(response=...)
that it returns the list of this pydantic model instances, something similar as you can do with DRF serializer usingmany=True
... however I did not find a way how I can make this work correctly... Can you please help me what is a way of doing so? I've triedTypeAdapter
,List[MyModel]
and some other combinations, but neither of them seems to return correct openapi schema with correctly defined refs in#/components/schemas/{model}
... Thanks a lot!