Я строю обобщенную модель Pydantic (давайте назовем ее модель X), которую я хочу использовать для сопоставления и извлечения значений из нескольких различных схем JSON (модель A, B, C и т. Д.). Эти схемы получают через API и не могут быть изменены в источнике. (DATAMODEL_CODE_GENERATOR) < /li>
[*] Получить мою обобщенную схему -> генерировать пижантическую модель x < /li>
Создать пустой экземпляр обобщенной модели x (проблематично из -за необходимых полей) < /li>
Совместитель A с моделью x < /li>
x. Если битх имеет систему. Строка в одной схеме и списке в другой) или ($ ref/имена подкласса различаются).
Требуемые поля в модели x делают «пустую, но полностью структурированную» версию. /> Создание полностью структурированного (но неопустокованного) экземпляра x < /li>
Совместные пути /типы между a и x, даже если имена $ refs различаются < /li>
Создать для гибкой популяции и проверки общих структур < /li>
< /ul>
?? Любой совет:
Что было бы хорошей стратегией для такого рода абстракции схемы и сопоставления экземпляров? class = "lang-json prettyprint-override">{
"required": ["systems", "results"],
"properties": {
"systems": {
"$ref": "#/definitions/System"
},
"results": {
"$ref": "#/definitions/ResultList"
}
},
"definitions": {
"System": {
"type": "object",
"required": ["vendor", "model", "type", "operator"],
"properties": {
"vendor": { "type": "string" },
"model": { "type": "string" },
"type": { "type": "string" },
"operator": { "type": "string" }
}
},
"Result": {
"type": "object",
"properties": {
"x": { "type": "integer" },
"y": { "type": "integer" }
},
"required": ["x", "y"]
},
"ResultList": {
"type": "array",
"items": { "$ref": "#/definitions/Result" }
}
}
}
< /code>
упрощенный пример схемы A < /h2>
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"required": ["systems", "users", "results"],
"properties": {
"systems": {
"type": "array",
"items": { "$ref": "#/definitions/turbineSystem" }
},
"users": {
"type": "array",
"items": { "$ref": "#/definitions/User" }
},
"results": {
"$ref": "#/definitions/ResultList"
}
},
"definitions": {
"turbineSystem": {
"type": "object",
"required": ["vendor", "model", "type", "serial_number"],
"properties": {
"vendor": { "type": "string" },
"model": { "type": "string" },
"type": {
"type": "array",
"items": { "type": "string" }
},
"serial_number": { "type": "string" }
}
},
"User": {
"type": "object",
"properties": {
"name": { "type": "string" }
}
},
"turbineResult": {
"type": "object",
"required": ["x", "y"],
"properties": {
"x": { "type": "string" }, // ← conflict: was integer in Generic
"y": { "type": "integer" }
}
},
"ResultList": {
"type": "array",
"items": { "$ref": "#/definitions/turbineResult" } // ← conflict: reference is different in Generic
}
}
}
я попробовал:
Сопоставьте структуру схемы JSON (модель A) с более простой общей/обобщенной схемой через модели пиданты для обеспечения типов. /> < /ul>
i ожидал: < /strong> < /p>
Для создания «шаблона» экземпляра модели x со значениями заполнителя /по умолчанию, чтобы его можно было заполнить с помощью модели x только из модели. и совпадать с полями (например, Systems []. Model, Results []. X и т. Д.)import json
import os
from datamodel_code_generator.parser.jsonschema import JsonSchemaParser
import tempfile
import importlib.util
import sys
from pydantic import BaseModel
## Works as it should
def get_pydantic_model_from_jsonschema(json_schema: dict) -> type[BaseModel]:
parser = JsonSchemaParser(str(json_schema))
model_code = parser.parse()
# Save to a temporary .py file - i only need to model during runtime
with tempfile.NamedTemporaryFile(delete=False, suffix=".py") as temp_file:
temp_file.write(model_code.encode('utf-8'))
temp_file_path = temp_file.name
# Import the generated module
spec = importlib.util.spec_from_file_location("generated_model", temp_file_path)
generated_model = importlib.util.module_from_spec(spec)
sys.modules["generated_model"] = generated_model
spec.loader.exec_module(generated_model)
os.remove(temp_file_path)
model_class = getattr(generated_model, "Model")
return model_class
# Doesn't work
def create_empty_instance(model_class: type[BaseModel]) -> BaseModel:
# Create an empty instance of the Pydantic model, with default values
def fill(model_cls: type[BaseModel]) -> dict:
result = {}
for field_name, field_info in model_cls.model_fields.items():
field_type = field_info.annotation
if field_type == str:
result[field_name] = ""
elif field_type == int:
result[field_name] = 0
elif field_type == bool:
result[field_name] = False
else:
result[field_name] = None
return result
return model_class(**fill(model_class))
# doesn't work
def populate_model_from_another(source_model: BaseModel, target_model: BaseModel) -> BaseModel:
# Copy matching fields from source model to target model
def add_matching_field_values(source: any, target: any):
for field in source.model_fields:
if field in target.model_fields:
src_val = getattr(source, field)
tgt_val = getattr(target, field)
# Recursive step for nested models
if isinstance(src_val, BaseModel) and isinstance(tgt_val, BaseModel):
add_matching_field_values(src_val, tgt_val)
elif isinstance(src_val, list) and isinstance(tgt_val, list):
for src_item, tgt_item in zip(src_val, tgt_val):
add_matching_field_values(src_item, tgt_item)
else:
setattr(target, field, src_val)
add_matching_field_values(source_model, target_model)
return target_model
# ___________________________________________________________________________________
# Load Model A (source) schema and instance
with open('model_a_schema.json', 'r') as f:
model_a_schema = json.load(f)
with open('model_a_data.json', 'r') as f:
model_a_data = json.load(f)
model_a_class = get_pydantic_model_from_jsonschema(model_a_schema)
model_a_instance = model_a_class(**model_a_data)
# Load Generic Model X schema
with open('generic_model_x_schema.json', 'r') as f:
generic_model_x_schema = json.load(f)
generic_model_x_class = get_pydantic_model_from_jsonschema(generic_model_x_schema)
# Does't work: Create empty instance/template
generic_model_x_instance = create_empty_instance(generic_model_x_class)
# Does't work: Populate the Generic Model X instance with matching data from Model A
populated_generic_model_x = populate_model_from_another(model_a_instance, generic_model_x_instance)
print(populated_generic_model_x)
Подробнее здесь: https://stackoverflow.com/questions/796 ... fields-fro
Как соответствовать и заполнить общую пиддантскую модель с глубоко вложенными полями из аналогичных, но связанных с согл ⇐ Python
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение