Пропуск уровней диктанта при распаковке вложенного JSON с помощью Pydantic

#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. Спасибо, это то, что я искал. Я пытался сделать это с помощью обычного валидатора и потерпел неудачу.