-
Notifications
You must be signed in to change notification settings - Fork 270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a blueprint for pydantic 2 #1028
Conversation
) | ||
auto_schema.registry.register_on_missing(component) | ||
|
||
return schema |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ℹ️ Here's the difference between the two blueprints for pydantic.
The change is to use model_json_schema()
instead of model_schema()
, which takes a ref_template
argument instead of ref_prefix
.
Note, I didn't see in the pydantic migration notes anything about migrating from the old model_schema()
.
$ diff -U5 docs/blueprints/pydantic.py docs/blueprints/pydantic2.py
--- docs/blueprints/pydantic.py 2023-07-17 13:38:19.059201949 +0200
+++ docs/blueprints/pydantic2.py 2023-07-17 13:41:14.883652117 +0200
@@ -1,9 +1,9 @@
from drf_spectacular.extensions import OpenApiSerializerExtension
from drf_spectacular.plumbing import ResolvedComponent
-from pydantic.schema import model_schema
+from pydantic.json_schema import model_json_schema
class PydanticExtension(OpenApiSerializerExtension):
target_class = "pydantic.BaseModel"
match_subclasses = True
@@ -12,11 +12,11 @@
return self.target.__name__
def map_serializer(self, auto_schema, direction):
# let pydantic generate a JSON schema
- schema = model_schema(self.target, ref_prefix="#/components/schemas/")
+ schema = model_json_schema(self.target, ref_template="#/components/schemas")
# pull out potential sub-schemas and put them into component section
for sub_name, sub_schema in schema.pop("definitions", {}).items():
component = ResolvedComponent(
name=sub_name,
Codecov ReportPatch and project coverage have no change.
Additional details and impacted files@@ Coverage Diff @@
## master #1028 +/- ##
=======================================
Coverage 98.55% 98.55%
=======================================
Files 68 68
Lines 8367 8367
=======================================
Hits 8246 8246
Misses 121 121 ☔ View full report in Codecov by Sentry. |
awesome! thx @caarmen |
Actually, it seems there's an issue, sorry I didn't catch it earlier :/ For a model with a field which is a list of another pydantic model, the field isn't being generated correctly. Looks the pydantic 1 I'll update here if/when I find more information. |
yes, I also noticed the 2 versions are subtly different. Stuff wasn't just renamed. Feel free to do another PR. |
I hit an issue trying to work around this. I opened an issue on Pydantic: pydantic/pydantic#6741 I haven't managed to generate an openapi json with either Looks like pydantic has an api to be able to put definitions in Maybe (hopefully) I just didn't understand the pydantic api enough. 🤞🏻 |
I've figured out a workaround, but it's not very clean :/ It basically takes the Tested in my project: +import json
+
from drf_spectacular.extensions import OpenApiSerializerExtension
from drf_spectacular.plumbing import ResolvedComponent
from pydantic.json_schema import model_json_schema
class PydanticExtension(OpenApiSerializerExtension):
target_class = "pydantic.BaseModel"
match_subclasses = True
def get_name(self, auto_schema, direction):
return self.target.__name__
def map_serializer(self, auto_schema, direction):
# let pydantic generate a JSON schema
- schema = model_json_schema(self.target, ref_template="#/components/schemas")
+ schema = model_json_schema(self.target)
# pull out potential sub-schemas and put them into component section
- for sub_name, sub_schema in schema.pop("definitions", {}).items():
+ 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)
- return schema
+ # Workaround to force placing definitions in components/schemas.
+ # Pydantic places definitions in $defs, and we want them in components/schemas,
+ # but using ref_template="#/components/schemas in model_json_schema() makes us lose sub objects.
+ # See https://github.com/pydantic/pydantic/issues/6741
+ schema_with_relocated_defs = json.loads(json.dumps(schema).replace("#/$defs/", "#/components/schemas/"))
+ return schema_with_relocated_defs
If you want, I can open a PR for this. But I understand it's not very clean! 😄 We can wait for some news on the pydantic issue instead. |
scratch that, I can do a proper fix I think 😁 |
Here's a PR: My confidence in this isn't at 100% for now, we could say 😅 . So do feel free to try it out a bit before merging. I didn't find unit tests for blueprints in the project. |
Add a blueprint to support pydantic models, using the pydantic 2.x version.
Here's the pydantic 2 migration guide: https://docs.pydantic.dev/latest/migration/