#python #pydantic
Вопрос:
Я извлекаю данные из API и получаю ответ JSON примерно так:
{
"features": {
"due_dates": {
"enabled": true,
"start_date": false,
"remap_due_dates": true,
"remap_closed_due_date": false
},
"sprints": {
"enabled": false
},
"points": {
"enabled": false
},
"custom_items": {
"enabled": false
},
"tags": {
"enabled": true
},
"time_estimates": {
"enabled": true
},
"checklists": {
"enabled": true
},
"zoom": {
"enabled": false
},
"milestones": {
"enabled": false
},
"custom_fields": {
"enabled": true
},
"remap_dependencies": {
"enabled": true
},
"dependency_warning": {
"enabled": true
},
"multiple_assignees": {
"enabled": true
},
"portfolios": {
"enabled": true
},
"emails": {
"enabled": true
}
}
У меня есть такая настройка класса:
class Features(BaseModel):
multiple_assignees: bool = False
start_date: bool = False
remap_due_dates: bool = False
remap_closed_due_date: bool = False
time_tracking: bool = False
tags: bool = False
time_estimates: bool = False
checklists: bool = False
custom_fields: bool = False
remap_dependencies: bool = False
dependency_warning: bool = False
portfolios: bool = False
points: bool = False
custom_items: bool = False
zoom: bool = False
milestones: bool = False
emails: bool = False
Что я хотел бы сделать, так это распаковать этот JSON в объект features и использовать значение из ключа «включено» для каждого соответствующего атрибута. Я хочу сделать это таким образом, чтобы избежать необходимости настраивать класс для спринтов, точек, пользовательских элементов и т. Д. Можно ли просто получить вложенные «включенные» значения bool и пропустить настройку класса для каждого?
Ответ №1:
К сожалению, я не думаю, что есть очень простой способ сделать это. Я думаю, что самым простым способом было бы использовать корневой валидатор, как упоминалось в этом выпуске, чтобы мы могли разворачивать поля, используя нашу собственную желаемую логику. Что-то вроде этого должно сработать для этого:
import json
from pydantic import BaseModel, root_validator
class Features(BaseModel):
multiple_assignees: bool = False
start_date: bool = False
remap_due_dates: bool = False
remap_closed_due_date: bool = False
time_tracking: bool = False
tags: bool = False
time_estimates: bool = False
checklists: bool = False
custom_fields: bool = False
remap_dependencies: bool = False
dependency_warning: bool = False
portfolios: bool = False
points: bool = False
custom_items: bool = False
zoom: bool = False
milestones: bool = False
emails: bool = False
@root_validator(pre=True)
def extract_features(cls, v):
# Unwrap features and all 'enabled' values for each field within
res = {k: v['enabled'] if isinstance(v, dict) and 'enabled' in v else v
for k, v in v['features'].items()}
# Map due date fields which are a bit different
due_dates = v['features'].get('due_dates')
if due_dates:
for field in ('start_date',
'remap_due_dates',
'remap_closed_due_date'):
res[field] = due_dates.get(field, False)
return res
string = """
{
"features": {
"due_dates": {
"enabled": true,
"start_date": false,
"remap_due_dates": true,
"remap_closed_due_date": false
},
"sprints": {
"enabled": false
},
"points": {
"enabled": false
},
"custom_items": {
"enabled": false
},
"tags": {
"enabled": true
},
"time_estimates": {
"enabled": true
},
"checklists": {
"enabled": true
},
"zoom": {
"enabled": false
},
"milestones": {
"enabled": false
},
"custom_fields": {
"enabled": true
},
"remap_dependencies": {
"enabled": true
},
"dependency_warning": {
"enabled": true
},
"multiple_assignees": {
"enabled": true
},
"portfolios": {
"enabled": true
},
"emails": {
"enabled": true
}
}
}
"""
d = json.loads(string)
x = Features(**d)
print(x)
Комментарии:
1. Спасибо, это то, что я искал. Я пытался сделать это с помощью обычного валидатора и потерпел неудачу.