如何在使用Pydantic创建嵌套JSON Schema时移除$defs和$ref?
如何移除Pydantic生成的JSON Schema中的*$defs和$ref*?
我通过以下代码用Pydantic生成JSON Schema:
from pydantic import BaseModel, Field import json class VendorInfo(BaseModel): vendor_name: str = Field("", description= "Vendor Name") vendor_vat_no: str = Field("", description= "Vendor VAT Number") class InvoiceHeader(BaseModel): invoice_number: str = Field("", description= "The unique invoice number") invoice_date: str = Field("", description= "The date invoice was created") vendor_info: VendorInfo = Field("", description= "Description of the vendor") print(json.dumps(InvoiceHeader.model_json_schema(), indent=2))
运行后得到包含*$defs和$ref*的输出:
{ "$defs": { "VendorInfo": { "properties": { "vendor_name": { "default": "", "description": "Vendor Name", "title": "Vendor Name", "type": "string" }, "vendor_vat_no": { "default": "", "description": "Vendor VAT Number", "title": "Vendor Vat No", "type": "string" } }, "title": "VendorInfo", "type": "object" } }, "properties": { "invoice_number": { "default": "", "description": "The unique invoice number", "title": "Invoice Number", "type": "string" }, "invoice_date": { "default": "", "description": "The date invoice was created", "title": "Invoice Date", "type": "string" }, "vendor_info": { "$ref": "#/$defs/VendorInfo", "default": "", "description": "Description of the vendor" } }, "title": "InvoiceHeader", "type": "object" }
请问如何移除生成Schema中的*$defs和$ref*,得到完全内嵌的结构?
解决方法
方法1:手动递归解析并替换引用
写一个递归函数遍历Schema结构,将所有*$ref指向的内容从$defs中取出并替换原引用字段,最后删除$defs*字段。
示例代码:
from pydantic import BaseModel, Field import json class VendorInfo(BaseModel): vendor_name: str = Field("", description= "Vendor Name") vendor_vat_no: str = Field("", description= "Vendor VAT Number") class InvoiceHeader(BaseModel): invoice_number: str = Field("", description= "The unique invoice number") invoice_date: str = Field("", description= "The date invoice was created") vendor_info: VendorInfo = Field("", description= "Description of the vendor") def dereference_schema(schema): def _deref(obj): if isinstance(obj, dict): if "$ref" in obj: # 提取引用的定义名称 ref_name = obj["$ref"].split("/")[-1] ref_def = schema["$defs"][ref_name] # 保留原字段的额外属性(比如default、description) ref_def.update({k: v for k, v in obj.items() if k != "$ref"}) return ref_def # 递归处理字典内的每个字段 for key, value in obj.items(): obj[key] = _deref(value) elif isinstance(obj, list): # 递归处理列表内的每个元素 for idx, item in enumerate(obj): obj[idx] = _deref(item) return obj # 深拷贝原Schema避免修改原始数据 dereferenced_schema = json.loads(json.dumps(schema)) dereferenced_schema = _deref(dereferenced_schema) # 删除不再需要的$defs字段 if "$defs" in dereferenced_schema: del dereferenced_schema["$defs"] return dereferenced_schema # 生成并处理Schema raw_schema = InvoiceHeader.model_json_schema() flattened_schema = dereference_schema(raw_schema) print(json.dumps(flattened_schema, indent=2))
运行后得到完全内嵌的Schema:
{ "properties": { "invoice_number": { "default": "", "description": "The unique invoice number", "title": "Invoice Number", "type": "string" }, "invoice_date": { "default": "", "description": "The date invoice was created", "title": "Invoice Date", "type": "string" }, "vendor_info": { "default": "", "description": "Description of the vendor", "properties": { "vendor_name": { "default": "", "description": "Vendor Name", "title": "Vendor Name", "type": "string" }, "vendor_vat_no": { "default": "", "description": "Vendor VAT Number", "title": "Vendor Vat No", "type": "string" } }, "title": "VendorInfo", "type": "object" } }, "title": "InvoiceHeader", "type": "object" }
方法2:使用第三方库自动解引用
如果不想手动编写递归逻辑,可以用json-schema-ref-parser库自动处理所有引用关系。
首先安装库:
pip install json-schema-ref-parser
然后使用库的dereference方法处理Schema:
from pydantic import BaseModel, Field import json from jsonschema_ref_parser import dereference class VendorInfo(BaseModel): vendor_name: str = Field("", description= "Vendor Name") vendor_vat_no: str = Field("", description= "Vendor VAT Number") class InvoiceHeader(BaseModel): invoice_number: str = Field("", description= "The unique invoice number") invoice_date: str = Field("", description= "The date invoice was created") vendor_info: VendorInfo = Field("", description= "Description of the vendor") raw_schema = InvoiceHeader.model_json_schema() # 自动解引用所有$ref flattened_schema = dereference(raw_schema) # 移除残留的$defs字段 if "$defs" in flattened_schema: del flattened_schema["$defs"] print(json.dumps(flattened_schema, indent=2))
这个方法适合处理复杂嵌套的Schema,无需手动维护递归逻辑。
内容的提问来源于stack exchange,提问作者Soumadeep Dutta
相关产品推荐
相关产品推荐

