Skip to content

Latest commit

 

History

History
849 lines (587 loc) · 80.7 KB

Модуль 11 - Сериализация. Marshmallow Ч3.md

File metadata and controls

849 lines (587 loc) · 80.7 KB

%%

Напиши максимально простой пример использования этой библиотеки. Используй dump и load. А так же дай деатльные пояснения. Без использования marshmallow_dataclasses Используй pre_load для обработки данных (чтобы достать данные из вложенного словаря координат) если это возможно Используй post_load для десериализации в экземпляр класса Обработай всю коллекцию за 1 проход Используй этот набор данных для примера.

@dataclass
class City:
name: str
population: int
district: str
subject: str
lat: float
lon: float
email: str

cities_list = [
{ "coords": {
"lat": "52.65",
"lon": "90.08333"
},
"district": "Сибирский",
"name": "Абаза",
"population": 14816,
"subject": "Хакасия"
},
{ "coords": {
"lat": "53.71667",
"lon": "91.41667"
},
"district": "Сибирский",
"name": "Абакан",
"population": 187239,
"subject": "Хакасия"
}]

%%

Что такое Marshmallow

[!info] Библиотека Marshmallow в Python — это инструмент, который помогает программистам превращать сложные данные (например, объекты классов Python) в более простые структуры, которые легко преобразовывать в формат JSON, а также делать обратное преобразование из JSON в объекты Python. Это особенно полезно при разработке веб-приложений, когда нужно отправлять и получать данные через интернет.

Чтобы понять, для чего нужна Marshmallow, представьте, что у вас есть приложение, где пользователи могут регистрироваться, входить в систему и обмениваться сообщениями. Каждый пользователь и сообщение в вашем приложении представлены сложными объектами в вашем коде. Однако, когда вы хотите отправить информацию о пользователе или сообщении через интернет другому пользователю или серверу, эти сложные объекты нужно преобразовать в формат, который легко читается и интерпретируется различными системами и языками программирования. Самым распространенным таким форматом является JSON.

Вот здесь на сцену выходит Marshmallow. Эта библиотека позволяет вам легко:

  1. Сериализация: преобразование объектов Python (например, моделей данных вашего приложения) в словари Python, которые затем можно легко превратить в строку JSON. Это полезно, когда вы хотите отправить данные из вашего приложения на внешний сервер или клиент.

  2. Десериализация: обратный процесс, при котором данные в формате JSON преобразуются обратно в объекты Python. Это полезно, когда ваше приложение получает данные в формате JSON, например, от веб-формы или внешнего API, и вам нужно использовать эти данные в вашем приложении как объекты Python.

Кроме того, Marshmallow помогает валидировать данные, то есть проверять их на соответствие определенным правилам или ограничениям. Например, если вы ожидаете, что пользователь введет свой возраст как число, Marshmallow может проверить, что полученное значение действительно является числом, и выдать ошибку, если это не так.

В общем, Marshmallow упрощает работу с данными между вашим Python-приложением и внешним миром, делая процессы сериализации, десериализации и валидации данных более простыми и безопасными.


Схема (Schema) и Поле (Field)

В библиотеке Marshmallow сущности "схема" (Schema) и "поле" (Field) играют ключевую роль в процессе сериализации и десериализации данных. Понимание этих сущностей важно для эффективного использования библиотеки. Давайте рассмотрим каждую из них подробнее.

Схема (Schema)

Схема в Marshmallow — это класс, который определяет, как данные должны быть сериализованы (преобразованы в простые типы данных, например, в словарь или строку JSON) или десериализованы (преобразованы обратно в сложные типы данных, например, в объекты Python). Схема работает как карта или шаблон, указывая, какие поля данных присутствуют, как они должны обрабатываться и какие дополнительные проверки или преобразования могут потребоваться при этом обработке.

Основная роль схемы — упростить процесс преобразования данных, обеспечив при этом их валидацию и соблюдение структуры. Схемы позволяют определить, какие поля включать в сериализованные данные, какие исключать, как обрабатывать отсутствующие или дополнительные поля и как преобразовывать типы данных между Python и форматом, пригодным для обмена данными (например, JSON).

Поле (Field)

Поля в Marshmallow — это компоненты схемы, каждый из которых соответствует определенному элементу данных. Поле определяет тип данных (например, строка, число, дата), который оно представляет, и содержит логику для его сериализации и десериализации и валдации. Поля могут также содержать дополнительные параметры для валидации (например, обязательное поле, ограничения длины для строк) и преобразования данных (например, преобразование строки в дату).

Каждое поле в схеме Marshmallow представляет собой инстанс класса, производного от базового класса Field. Библиотека предоставляет множество готовых классов полей для различных типов данных, таких как String для строк, Integer для целых чисел, Float для чисел с плавающей точкой, DateTime для даты и времени и многих других. Разработчики могут также создавать свои собственные классы полей для обработки специфических типов данных или выполнения особых задач сериализации/десериализации.

Ключевые аспекты работы с полями:

  • Сериализация: поля преобразуют данные из сложных объектов Python в формат, подходящий для JSON (или других форматов), например, преобразование объекта даты в строку.
  • Десериализация: поля преобразуют данные из простого формата (например, из JSON) обратно в сложные типы данных Python, например, строку в объект даты.
  • Валидация: поля могут проверять данные на соответствие определенным условиям или ограничениям, например, что число не отрицательное или что строка соответствует определенному шаблону.

Вместе схема и поля позволяют точно и гибко управлять процессом сериализации и десериализации данных, обеспечивая при этом их корректность и соответствие заданным требованиям. Это облегчает обмен данными между различными частями приложения или между разными системами, делая код более чистым, понятным и безопасным.

Поля могут быть настроены на выполнение различных задач помимо основных преобразований типов и валидации. Например, можно задать параметры по умолчанию для полей, которые будут использоваться, если соответствующие данные отсутствуют при десериализации. Также поля могут быть настроены на пропуск значений, если они отсутствуют при сериализации, что может быть полезно для управления представлением данных при отправке клиенту.

Применение схемы и полей

В контексте веб-разработки и API, схемы и поля Marshmallow особенно полезны для следующих задач:

  • Подготовка данных для ответов API: Сериализация объектов данных в формат JSON для отправки клиентам через HTTP ответы.
  • Обработка и проверка входящих данных: Десериализация и валидация данных, полученных от клиентов, например, в JSON формате через HTTP запросы, для последующего использования в приложении.
  • Преобразование между различными представлениями данных: Например, преобразование между сложными объектами доменной модели и более простыми структурами данных, подходящими для хранения в базе данных или кеширования.

Важность валидации

Один из ключевых аспектов использования схем и полей — возможность валидации данных. Валидация позволяет убедиться, что данные, получаемые от пользователей или других внешних источников, соответствуют ожидаемым требованиям и ограничениям, прежде чем они будут использованы в приложении. Это важный элемент безопасности и надежности приложений, так как предотвращает использование некорректных или злонамеренных данных.

Заключение

Схемы и поля в Marshmallow формируют мощный инструментарий для работы с данными в приложениях на Python. Они обеспечивают гибкость и контроль над процессом сериализации и десериализации данных, позволяя разработчикам фокусироваться на логике приложения, не беспокоясь о деталях реализации обмена данными и обработки форматов. Валидация данных на уровне схемы и полей способствует созданию более безопасных и надежных приложений, защищая от некорректных входных данных и обеспечивая корректность обработки данных на всех этапах работы приложения.


Простой практический пример

Давайте использовать библиотеку Marshmallow для того, чтобы преобразовать данные из списка словарей cities_list в объекты класса City, а также наоборот. Прежде всего, определим класс City, который будет представлять данные о городе, и затем создадим схему Marshmallow для сериализации и десериализации этих данных.

Шаг 1: Определение класса данных

from dataclasses import dataclass

@dataclass
class City:
    name: str
    population: int
    district: str
    subject: str
    lat: float
    lon: float
    email: str  # Добавим поле email, но оно не будет заполняться из нашего списка, так как там его нет.

cities_list = [  
  {    "coords": {  
      "lat": "52.65",  
      "lon": "90.08333"  
    },  
    "district": "Сибирский",  
    "name": "Абаза",  
    "population": 14816,  
    "subject": "Хакасия"  
  },  
  {    "coords": {  
      "lat": "53.71667",  
      "lon": "91.41667"  
    },  
    "district": "Сибирский",  
    "name": "Абакан",  
    "population": 187239,  
    "subject": "Хакасия"  
  }]

Шаг 2: Создание схемы Marshmallow

Следующим шагом будет создание схемы Marshmallow. Схема определяет, как поля объекта City соотносятся с данными в словаре (и наоборот).

from marshmallow import Schema, fields, post_load

class CitySchema(Schema):
    name = fields.Str()
    population = fields.Int()
    district = fields.Str()
    subject = fields.Str()
    lat = fields.Float()
    lon = fields.Float()
    email = fields.Email(missing="[email protected]")  # Устанавливаем значение по умолчанию для email
    
    # Функция post_load не используется по вашей просьбе.

Шаг 3: Сериализация и десериализация данных

Теперь, когда у нас есть класс данных и схема, мы можем сериализовать объекты City в словари и десериализовать данные из списка cities_list в объекты City.

Десериализация

Преобразуем словари из списка cities_list в объекты City. Поскольку в исходных данных координаты находятся во вложенном словаре coords, нам нужно немного их преобразовать перед десериализацией.

# Создаём экземпляр схемы
schema = CitySchema()

# Пример десериализации для первого города в списке
example_city_dict = cities_list[0]
example_city_dict["lat"] = example_city_dict["coords"]["lat"]
example_city_dict["lon"] = example_city_dict["coords"]["lon"]
# Удаляем вложенный словарь 'coords', так как он больше не нужен
del example_city_dict["coords"]

# Десериализация словаря в объект City
city_object = schema.load(example_city_dict)
print(city_object)

Сериализация

Теперь преобразуем объект City обратно в словарь.

# Сериализация объекта City в словарь
city_dict = schema.dump(city_object)
print(city_dict)

Пояснения

  • Сериализация (преобразование объекта в словарь) полезна, когда нужно сохранить объект в базе данных или отправить его через API.
  • Десериализация (преобразование словаря в объект) удобна для создания объектов на основе данных, полученных из внешних источников, например, из запросов к API или из файлов JSON.

В этом примере мы использовали CitySchema для описания, как данные должны быть преобразованы из словаря в объект City и обратно, а также установили значение по умолчанию для поля email, которое отсутствует в исходных данных.

Немного больше возмодностей

Давайте разберём несколько продвинутых возможностей библиотеки Marshmallow, которые делают её ещё более мощным инструментом для работы с сериализацией и десериализацией данных, а также для валидации.

Декораторы @pre_load и @post_load

Декораторы @pre_load и @post_load используются для выполнения кода до или после десериализации данных соответственно. Это позволяет разработчикам добавлять дополнительную логику обработки данных, которая не ограничивается стандартным процессом преобразования и валидации, предоставляемым полями схемы.

  • @pre_load: Этот декоратор применяется к методам схемы, которые должны быть вызваны перед началом процесса десериализации. Это может быть полезно для предварительной обработки входных данных, например, для нормализации данных или для преобразования форматов данных, не поддерживаемых стандартными полями.

  • @post_load: Декоратор @post_load используется для методов, которые вызываются после того, как данные были десериализованы в объект. Это может быть полезно для пост-обработки объекта, например, для установки дополнительных атрибутов, которые вычисляются на основе других атрибутов объекта, или для преобразования промежуточного объекта в окончательный объект вашей модели.

Валидация коллекции целиком

Marshmallow позволяет не только валидировать отдельные поля, но и обеспечивает возможность валидации всей коллекции (например, списка или словаря) целиком. Это означает, что можно проверить данные на более высоком уровне, например, убедиться, что список элементов содержит элементы уникальные по определённому признаку или что комбинация значений в словаре удовлетворяет определённым условиям. Такая возможность особенно полезна, когда требуется выполнить комплексные проверки, которые не могут быть связаны с одним конкретным полем.

Дополнительные инструменты и возможности

  • Вложенные схемы: Marshmallow позволяет определять вложенные схемы, что особенно полезно при работе со сложными структурами данных, содержащими вложенные объекты. Это позволяет точно описать, как должны быть сериализованы и десериализованы вложенные данные, обеспечивая при этом их корректность и соответствие структуре.

  • Поля со множественными значениями: С помощью специальных полей, таких как List или Dict, можно описывать поля, содержащие множество значений (например, списки или словари). Это позволяет удобно работать с коллекциями данных, сериализовывая и десериализовывая их содержимое.

  • Методы validate: Marshmallow предоставляет возможность валидации данных на уровне схемы с помощью вызова метода validate. Это позволяет проверить данные перед их обработкой и, в случае обнаружения ошибок, получить детальную информацию о них.

  • Кастомизация сообщений об ошибках: В Marshmallow можно не только валидировать данные, но и настраивать сообщения об ошибках валидации для каждого поля. Это позволяет предоставлять более понятные и детализированные сообщения пользователям или разработчикам, что упрощает процесс отладки и повышает удобство использования API или приложения в целом.

  • Условное включение полей: Существует возможность динамически включать или исключать поля из сериализации в зависимости от определённых условий. Это может быть полезно, например, для адаптации ответов API в соответствии с правами доступа пользователя или для оптимизации передаваемых данных в зависимости от контекста запроса.

  • Автоматическое создание документации: Используя схемы Marshmallow, можно автоматически генерировать документацию для API. Поскольку схемы точно описывают структуру данных, они могут быть использованы инструментами для генерации документации, что упрощает поддержку актуальной и точной документации для внешних разработчиков.

  • Интеграция с ORМ библиотеками: Marshmallow может быть интегрирован с различными ORМ библиотеками (например, SQLAlchemy), что позволяет упростить преобразование данных между форматом, пригодным для базы данных, и форматом, используемым в приложении или API. Это значительно сокращает количество шаблонного кода, необходимого для работы с данными.

  • Кастомные поля и валидаторы: Для обработки специфических требований к данным или для валидации, которая не поддерживается стандартными полями и валидаторами, Marshmallow позволяет создавать кастомные поля и валидаторы. Это предоставляет практически неограниченные возможности для адаптации библиотеки под конкретные нужды проекта.

  • Оптимизация производительности с помощью кэширования: Для повышения производительности сериализации и десериализации Marshmallow поддерживает кэширование определений схем и полей. Это позволяет сократить время обработки данных, особенно при работе с большими объёмами данных или сложными структурами.

В целом, Marshmallow предлагает богатый набор инструментов для работы с сериализацией и десериализацией данных, а также для валидации. Благодаря своей гибкости и расширяемости, Marshmallow может быть адаптирован под практически любые требования к работе с данными, делая процесс разработки более эффективным и безопасным.

Пример №2

Для реализации этой задачи мы сначала определим класс City, который будет представлять данные о городе. Затем создадим схему Marshmallow для обработки этих данных, включая декораторы @pre_load для предварительной обработки вложенных координат и @post_load для создания экземпляров City из десериализованных данных. Наконец, мы обработаем весь список городов за один проход, используя эти настройки.

Определение класса City

from dataclasses import dataclass

@dataclass
class City:
    name: str
    population: int
    district: str
    subject: str
    lat: float
    lon: float
    email: str  # Это поле будет игнорироваться при десериализации, так как в данных его нет.

Создание схемы Marshmallow с декораторами

from dataclasses import dataclass
from marshmallow import Schema, fields, pre_load, post_load


@dataclass
class City:
    name: str
    population: int
    district: str
    subject: str
    lat: float
    lon: float
    email: str


cities_list = [
    {"coords": {
        "lat": "52.65",
        "lon": "90.08333"
    },
        "district": "Сибирский",
        "name": "Абаза",
        "population": 14816,
        "subject": "Хакасия"
    },

    {"coords": {
        "lat": "53.71667",
        "lon": "91.41667"
                },
        "district": "Сибирский",
        "name": "Абакан",
        "population": 187239,
        "subject": "Хакасия"
    }]


class CitySchema(Schema):
    name = fields.Str()
    population = fields.Int()
    district = fields.Str()
    subject = fields.Str()
    lat = fields.Float()
    lon = fields.Float()
    email = fields.Str(load_default='[email protected]')  # Устанавливаем значение по умолчанию для email

    @pre_load()
    def unwrap_coords(self, data, **kwargs):
        # Этот метод будет вызван до десериализации каждого элемента списка.
        # Он изменяет структуру данных, извлекая координаты из вложенного словаря.
        # Делаем копию словаря, чтобы не изменять оригинальные данные
        data = data.copy()
        data.update({
            'lat': data['coords']['lat'],
            'lon': data['coords']['lon']
        })
        del data['coords']  # Удаляем исходный вложенный словарь координат
        return data

    @post_load
    def make_city(self, data, **kwargs):
        # Этот метод создает экземпляр City из десериализованных данных.
        return City(**data)


schema_many = CitySchema(many=True)
schema = CitySchema()

# Поштучно и множественно
cities = schema_many.load(cities_list)
print(cities)
city = schema.load(cities_list[0])
print(city)

# Сериализация - пробуем сделать dump
city2 = schema.dump(city)
print(city2)

Этот код демонстрирует использование библиотеки Marshmallow для сериализации и десериализации данных, а также некоторые продвинутые возможности, такие как обработка вложенных структур данных и создание экземпляров классов.

Что делает код:

  1. Определение класса данных City: Здесь используется декоратор @dataclass из модуля dataclasses, чтобы определить простой класс City с атрибутами, соответствующими данным о городе. Это включает в себя название, население, район, субъект, координаты и электронную почту.

  2. Подготовка данных cities_list: Создается список словарей, каждый из которых содержит информацию о городе, включая координаты во вложенном словаре.

  3. Создание схемы CitySchema с помощью Marshmallow:

    • Определение полей: Для каждого атрибута класса City определяется соответствующее поле Marshmallow. Например, name = fields.Str() указывает, что name является строкой. Для поля email устанавливается значение по умолчанию.
    • Метод @pre_load: Используется для предварительной обработки каждого элемента списка перед его десериализацией. В этом методе координаты извлекаются из вложенного словаря coords и добавляются непосредственно в основной словарь, после чего coords удаляется.
    • Метод @post_load: После десериализации данных в словарь, этот метод используется для создания экземпляра класса City, используя десериализованные данные.
  4. Десериализация данных:

    • С использованием CitySchema(many=True), обрабатывается список словарей cities_list, преобразуя его в список экземпляров класса City. Это демонстрирует возможность работы со множеством элементов за один проход.
    • Также показана десериализация отдельного элемента списка для создания одного экземпляра City.
  5. Сериализация данных: Используя метод dump, экземпляр City сериализуется обратно в словарь. Это позволяет преобразовать объекты Python в формат, подходящий для передачи данных или сохранения.

Ключевые моменты:

  • Предварительная и постобработка данных: Демонстрируется, как можно модифицировать данные перед и после процесса десериализации, что особенно полезно при работе со сложными структурами данных.
  • Универсальность обработки: Показывается, как одна и та же схема может быть использована как для обработки отдельных элементов, так и для работы с целым списком данных.
  • Сериализация и десериализация: Пример иллюстрирует, как данные могут быть преобразованы из словарей в объекты и обратно, что является ключевой особенностью Marshmallow.

В итоге, код демонстрирует, как Marshmallow упрощает обработку и валидацию данных при разработке приложений, особенно когда необходимо работать с вложенными структурами или автоматически создавать объекты на основе данных.

А что еще может быть в полях?

Поля в Marshmallow являются основными строительными блоками схем, и они используются для определения того, как данные должны быть сериализованы (преобразованы в простой формат, например, в JSON) или десериализованы (преобразованы обратно в сложные типы данных, например, в объекты Python). В скобках у каждого поля вы можете указать различные параметры и валидаторы, которые определяют, как должно обрабатываться содержимое этого поля. Давайте рассмотрим наиболее распространенные из них.

Общие параметры полей

  • required: Определяет, является ли поле обязательным для заполнения. Если поле отмечено как обязательное, но отсутствует во входных данных, Marshmallow сгенерирует ошибку.
  • missing: Задает значение по умолчанию для поля, если оно отсутствует во входных данных при десериализации.
  • default: Устанавливает значение по умолчанию для поля при сериализации, если значение атрибута объекта отсутствует.
  • allow_none: Указывает, может ли поле принимать значение None.
  • validate: Принимает функцию валидации или список функций, которые вызываются для проверки значения поля. Если значение не проходит валидацию, будет сгенерирована ошибка.
  • error_messages: Словарь, который позволяет переопределить стандартные сообщения об ошибках для различных типов ошибок валидации.

Специфические параметры для разных типов полей

Разные типы полей могут поддерживать дополнительные параметры, специфичные для их типа. Например:

  • String:
    • length: Может использоваться для указания минимальной и/или максимальной длины строки.
  • Number (включает Integer, Float):
    • strict: Указывает, должно ли поле строго соответствовать типу (например, только целым числам для Integer).
    • round (для Float): Определяет количество знаков после запятой, до которого следует округлить число при сериализации.
  • DateTime:
    • format: Строка формата, определяющая, как дата и время должны быть сериализованы или десериализованы.

Валидаторы

Валидаторы — это функции, которые используются для проверки данных. Marshmallow предоставляет несколько встроенных валидаторов, таких как проверка на минимальное/максимальное значение, соответствие регулярному выражению и т.д. Вы также можете определить свои собственные функции валидации. Валидаторы применяются к данным во время десериализации и могут генерировать ошибки, если данные не соответствуют заданным критериям.

Использование параметров полей

Параметры полей позволяют вам тонко настроить процесс сериализации и десериализации, обеспечивать корректность данных и генерировать понятные сообщения об ошибках для конечных пользователей или разработчиков, работающих с вашим API или приложением. Благодаря этим возможностям, Marshmallow облегчает создание надежных и удобных в использовании интерфейсов обмена данными, обеспечивая при этом высокий уровень контроля над процессом обработки данных.

Ключевые моменты, которые следует учитывать при работе с параметрами полей в Marshmallow:

  • Гибкость настройки: Параметры предоставляют возможность детально настроить обработку каждого поля в вашей схеме, начиная от базовой валидации и заканчивая сложными преобразованиями данных.
  • Улучшение взаимодействия с пользователем: Правильное использование параметров, таких как error_messages и validate, помогает предоставлять понятные сообщения об ошибках, что улучшает опыт работы с вашим приложением или API.
  • Валидация данных: Параметры валидации позволяют обеспечить, что данные не только корректно сериализуются и десериализуются, но и соответствуют определенным бизнес-правилам или требованиям безопасности.
  • Адаптация под специфические требования: Благодаря возможности создавать кастомные валидаторы и использовать специфические параметры для разных типов полей, Marshmallow позволяет адаптировать процесс работы с данными под почти любые специфические требования вашего приложения или сервиса.

Важно помнить, что правильное использование параметров полей не только повышает качество ваших данных, но и может существенно упростить логику обработки данных в вашем приложении, делая код более чистым и понятным.

В итоге, Marshmallow предоставляет мощный и гибкий инструментарий для работы с сериализацией и десериализацией данных, а также для их валидации. Понимание и правильное использование параметров полей позволит вам максимально эффективно использовать этот инструментарий для решения задач, связанных с обработкой и обменом данными.

Пример №3 вложенные схемы

from dataclasses import dataclass, field  
from marshmallow import Schema, fields, pre_load, post_load  
  
  
@dataclass  
class City:  
    name: str  
    population: int  
    district: str  
    subject: str  
    email: str  
    coords: dict = field(default_factory=dict)  
  
  
cities_list = [  
    {"coords": {  
        "lat": "52.65",  
        "lon": "90.08333"  
    },  
        "district": "Сибирский",  
        "name": "Абаза",  
        "population": 14816,  
        "subject": "Хакасия"  
    },  
  
    {"coords": {  
        "lat": "53.71667",  
        "lon": "91.41667"  
    },  
        "district": "Сибирский",  
        "name": "Абакан",  
        "population": 187239,  
        "subject": "Хакасия"  
    }]  
  
  
class CoordsSchema(Schema):  
    lat = fields.Float()  
    lon = fields.Float()  
  
  
class CitySchema(Schema):  
    name = fields.Str()  
    population = fields.Int()  
    district = fields.Str()  
    subject = fields.Str()  
    coords = fields.Nested(CoordsSchema)  
    email = fields.Str(load_default='[email protected]')  # Устанавливаем значение по умолчанию для email  
  
    @post_load  
    def make_city(self, data, **kwargs):  
        # Этот метод создает экземпляр City из десериализованных данных.  
  
        # return City(population=data['population'], district=data['district'],        #             subject=data['subject'], email=data['email'], coords=data['coords'], name=data['name'])  
        return City(**data)  
  
  
schema_many = CitySchema(many=True)  
schema = CitySchema()  
  
# Поштучно и множественно  
cities = schema_many.load(cities_list)  
print(cities)  
city = schema.load(cities_list[0])  
print(city)  
  
# Сериализация - пробуем сделать dump  
city2 = schema.dump(city)  
print(city2)

Пояснения

В этом коде реализуется процесс сериализации и десериализации данных о городах с использованием библиотеки Marshmallow и Python Dataclasses. Вот что происходит в каждом из его основных компонентов:

Определение класса City

  • Класс City создан как dataclass, что упрощает определение классов, автоматически добавляя специальные методы, включая __init__, __repr__, __eq__, и другие.
  • Этот класс имеет атрибуты для хранения информации о городе: имя, население, район, субъект, электронная почта и координаты. Координаты представлены словарем, созданным с использованием default_factory в field, что гарантирует, что по умолчанию coords будет пустым словарем, если при создании экземпляра класса City он не указан.

Подготовка данных о городах

  • Представлен список cities_list, содержащий информацию о двух городах, включая их координаты, население, район и субъект. Данные о координатах находятся во вложенном словаре.

Вложенная схема для координат

  • Класс CoordsSchema определяет схему для вложенного словаря координат, используя поля fields.Float() для широты (lat) и долготы (lon).

Определение основной схемы

  • Класс CitySchema определяет, как данные о городах должны быть десериализованы в экземпляры класса City и сериализованы обратно в словари.
  • Использует fields.Nested(CoordsSchema) для обработки вложенного словаря координат, указывая, что эти данные должны быть обработаны согласно схеме CoordsSchema.
  • Поле email использует параметр load_default, который указывает значение по умолчанию для этого поля при десериализации, если оно отсутствует в исходных данных.
  • Метод @post_load используется для создания и возврата экземпляра City после того, как данные были успешно десериализованы. **data позволяет передать десериализованные данные напрямую в конструктор City, автоматически распаковывая словарь в аргументы.

Десериализация и сериализация данных

  • Десериализация: schema_many.load(cities_list) преобразует список словарей с данными о городах в список экземпляров City, используя определенную выше схему. schema.load(cities_list[0]) делает то же самое, но только для первого города в списке.
  • Сериализация: schema.dump(city) преобразует экземпляр City обратно в словарь, используя ту же схему.

В итоге, этот код демонстрирует мощные возможности Marshmallow для обработки сложных структур данных, включая вложенные словари и автоматическое создание объектов на основе десериализованных данных.

marshmallow_dataclass

marshmallow_dataclass — это библиотека, которая сочетает в себе возможности двух мощных инструментов Python: dataclasses и Marshmallow. Это делается для упрощения и автоматизации процесса сериализации и десериализации данных, а также для обеспечения валидации данных при их преобразовании из/в Python объекты. Вот как это работает и для чего это нужно:

Зачем нужен marshmallow_dataclass

  • Автоматическое создание схем Marshmallow: Одна из основных задач при использовании Marshmallow — создание схем для сериализации и десериализации объектов. Это может быть довольно много шаблонного кода, если у вас много классов данных. marshmallow_dataclass автоматически генерирует эти схемы на основе классов данных (dataclasses), что сокращает количество кода и уменьшает вероятность ошибок.
  • Типизация и валидация: Python 3.6 и более поздние версии поддерживают аннотации типов, которые позволяют разработчикам указывать, какого типа должны быть атрибуты объектов. marshmallow_dataclass использует эту информацию для автоматической валидации данных при их сериализации/десериализации, гарантируя, что данные соответствуют ожидаемым типам и ограничениям.

Как это работает

Когда вы определяете класс данных с помощью dataclasses, вы можете указать типы атрибутов и, используя marshmallow_dataclass, автоматически генерировать схему Marshmallow для этого класса. Эта схема затем может быть использована для:

  • Сериализации объектов в JSON (или другие форматы): Это полезно для создания API, где вам нужно отправлять данные в формате, понятном клиентам (например, веб-браузерам).
  • Десериализации данных из внешних источников: Например, при получении данных в формате JSON от клиента, вы можете преобразовать их обратно в объекты Python для дальнейшей обработки.
  • Валидации данных: В процессе сериализации и десериализации данные автоматически проверяются на соответствие указанным типам и ограничениям. Это помогает предотвратить ошибки из-за некорректных данных.

Для чего это нужно

Использование marshmallow_dataclass особенно полезно в ситуациях, когда вы работаете с большим количеством классов данных в вашем приложении и хотите эффективно управлять процессом их сериализации/десериализации и валидации. Это обычно встречается в веб-разработке, при создании REST API, а также в любых приложениях, где требуется строгий контроль типов и форматов данных.

Сокращая количество шаблонного кода и автоматизируя создание схем, marshmallow_dataclass повышает эффективность разработки и обеспечивает более высокую надежность кода за счет строгой типизации и валидации данных.

from dataclasses import dataclass, field  
from marshmallow import Schema, fields, pre_load, post_load  
import marshmallow_dataclass  
  
  
@dataclass  
class City:  
    name: str  
    population: int  
    district: str  
    subject: str  
    coords: dict = field(default_factory=dict)  
  
  
cities_list = [  
    {"coords": {  
        "lat": "52.65",  
        "lon": "90.08333"  
    },  
        "district": "Сибирский",  
        "name": "Абаза",  
        "population": 14816,  
        "subject": "Хакасия"  
    },  
  
    {"coords": {  
        "lat": "53.71667",  
        "lon": "91.41667"  
    },  
        "district": "Сибирский",  
        "name": "Абакан",  
        "population": 187239,  
        "subject": "Хакасия"  
    }]  
  
  
# Создание схемы на основе датакласса  
CitySchema = marshmallow_dataclass.class_schema(City)  
  
# Создание экземпляра схемы  
city_schema = CitySchema(many=True)  
  
# Десериализация данных  
cities = city_schema.load(cities_list)  
print(cities)

Описание

В этом примере кода демонстрируется процесс создания класса данных для города (City), сериализации и десериализации списка таких городов с использованием библиотеки marshmallow_dataclass. Всё это выполняется без явного определения схемы Marshmallow, что упрощает и ускоряет процесс разработки.

Что делает код:

  1. Определение класса City: С помощью декоратора @dataclass создается класс City, который содержит информацию о городе, включая его название, население, район, субъект и координаты. Координаты представлены в виде словаря, который инициализируется как пустой по умолчанию с помощью field(default_factory=dict).

  2. Подготовка списка городов: Создается список словарей cities_list, каждый из которых содержит данные о конкретном городе, включая вложенный словарь с координатами (lat и lon).

  3. Использование marshmallow_dataclass для автоматического создания схемы: С помощью функции marshmallow_dataclass.class_schema, автоматически генерируется схема Marshmallow для класса City, основываясь на его определении. Это позволяет избежать ручного определения полей схемы, что обычно требуется при работе с Marshmallow напрямую.

  4. Сериализация и десериализация данных: Создается экземпляр схемы CitySchema с параметром many=True, который указывает, что схема предназначена для обработки списка объектов. Этот экземпляр затем используется для десериализации списка словарей cities_list в список экземпляров класса City. Результат показывается на экране.

Информация для Marshmallow

Особенности Marshmallow: Использование класса Meta

В Marshmallow класс Meta внутри схемы используется для настройки поведения самой схемы. Он позволяет задавать различные параметры, влияющие на сериализацию и десериализацию данных, валидацию, а также предоставляет возможность исключения или добавления определенных полей при сериализации.

Для реализации необязательности поля email и задания его значения по умолчанию через класс Meta в Marshmallow, можно использовать параметр load_default в определении поля схемы или указать это поведение непосредственно для класса данных, если используется автоматическая генерация схемы через marshmallow_dataclass.

Особенности marshmallow_dataclass: Метаинформация в полях

marshmallow_dataclass упрощает работу с датаклассами и Marshmallow, автоматически генерируя схемы на основе аннотаций типов и дополнительных параметров, передаваемых непосредственно в декораторы или функции поля (field). Это позволяет интегрировать настройки Marshmallow напрямую в определение датакласса, не требуя отдельного определения схемы.

Чтобы сделать поле email необязательным и задать значение по умолчанию при использовании marshmallow_dataclass, можно воспользоваться функцией field из модуля dataclasses, передав ей параметр metadata, в котором указывается словарь с настройками для Marshmallow. В этом словаре можно задать load_default, чтобы указать значение по умолчанию для поля email, если оно отсутствует в исходных данных.

Сравнение подходов

  • Использование класса Meta в Marshmallow — это классический подход, при котором настройки схемы задаются внутри определения самой схемы. Это обеспечивает гибкость и мощные возможности для настройки процесса сериализации/десериализации, но может потребовать дополнительного кода для определения схемы, отдельного от датакласса.

  • Метаинформация в полях с использованием marshmallow_dataclass позволяет интегрировать настройки сериализации и валидации непосредственно в определение датакласса, сокращая количество шаблонного кода и упрощая процесс создания и поддержки моделей данных. Этот подход идеально подходит для ситуаций, когда логика приложения тесно связана с структурой данных, и требуется автоматическая валидация и преобразование типов данных.

Оба подхода предлагают эффективные средства для работы с сериализацией и десериализацией данных в Python, выбор между ними зависит от конкретных требований проекта и предпочтений разработчика.

Пример №4

 from dataclasses import dataclass, field  
from marshmallow import Schema, fields, pre_load, post_load  
import marshmallow_dataclass  
  
  
@dataclass  
class City:  
    name: str  
    district: str  
    subject: str  
    population: int  
    email: str = field(default="", metadata={"load_default": "",  
                                             "load_only": True})  
    coords: dict = field(default_factory=dict)  
  
  
  
cities_list = [  
    {"coords": {  
        "lat": "52.65",  
        "lon": "90.08333"  
    },  
        "district": "Сибирский",  
        "name": "Абаза",  
        "population": -14816,  
        "subject": "Хакасия"  
    },  
  
    {"coords": {  
        "lat": "53.71667",  
        "lon": "91.41667"  
    },  
        "district": "Сибирский",  
        "name": "Абакан",  
        "population": 187239,  
        "subject": "Хакасия"  
    }]  
  
  
# Создание схемы на основе датакласса  
CitySchema = marshmallow_dataclass.class_schema(City)  
  
# Создание экземпляра схемы  
city_schema = CitySchema(many=True)  
  
# Десериализация данных  
cities = city_schema.load(cities_list)  
print(cities)  
  
# Сериализация данных  
data = city_schema.dump(cities)  
print(data)

Описание

Этот пример кода демонстрирует использование библиотеки marshmallow_dataclass для автоматического создания схемы Marshmallow из датакласса Python для сериализации и десериализации данных. Давайте разберём его по частям.

Определение класса City

Класс City определён с использованием декоратора @dataclass из модуля dataclasses. Этот класс представляет собой модель данных города с полями: название (name), район (district), субъект (subject), население (population), электронная почта (email) и координаты (coords).

Особенность поля email заключается в использовании параметра default для задания пустой строки как значения по умолчанию и в метаданных (metadata), которые содержат дополнительные настройки для Marshmallow:

  • "load_default": "" указывает, что при десериализации данных, если поле email отсутствует, должно использоваться пустое строковое значение.
  • "load_only": True означает, что это поле предназначено только для десериализации (загрузки данных), но не должно учитываться при сериализации (выгрузке данных).

Поле coords инициализируется с помощью default_factory=dict, что обеспечивает создание пустого словаря для координат, если при создании экземпляра City координаты не указаны.

Работа со списком городов

Список cities_list содержит словари с данными о двух городах. Эти данные включают вложенный словарь coords с широтой (lat) и долготой (lon).

Автоматическое создание схемы

marshmallow_dataclass.class_schema(City) автоматически генерирует схему Marshmallow на основе датакласса City. Эта схема используется для десериализации списка словарей cities_list в список экземпляров City, а также для последующей сериализации объектов City обратно в формат словаря.

Десериализация и сериализация данных

  • При десериализации (city_schema.load(cities_list)) данные из списка словарей преобразуются в список объектов City.
  • При сериализации (city_schema.dump(cities)) объекты City преобразуются обратно в список словарей.

Эти операции показывают, как данные могут быть загружены из внешнего источника, обработаны и затем представлены в нужном формате.

Дополнительные параметры через метаданные в датаклассе

Помимо указанных параметров (load_default, load_only), через метаданные можно передать и другие настройки для полей, используемых в Marshmallow, включая валидаторы (validate) и параметры валидаторов. Например, можно указать функцию валидации, которая проверит, что население города (population) является положительным числом, или задать регулярное выражение для проверки формата электронной почты.

Эти метаданные делают определение класса данных более мощным и гибким инструментом для управления процессом сериализации/десериализации и валидации данных, обеспечивая тем самым точность и надёжность обработки данных в приложениях.

Пример №5

 
from dataclasses import dataclass, field  
from marshmallow import Schema, fields, pre_load, post_load  
import marshmallow_dataclass  
from marshmallow.validate import Range  
  
  
@dataclass  
class City:  
    name: str  
    district: str  
    subject: str  
    population: int = field(metadata={'validate': Range(min=1, max=1000000)})  
    email: str = field(default="", metadata={"load_default": "",  
                                             "load_only": True})  
    coords: dict = field(default_factory=dict)  
  
  
  
cities_list = [  
    {"coords": {  
        "lat": "52.65",  
        "lon": "90.08333"  
    },  
        "district": "Сибирский",  
        "name": "Абаза",  
        "population": 14816,  
        "subject": "Хакасия"  
    },  
  
    {"coords": {  
        "lat": "53.71667",  
        "lon": "91.41667"  
    },  
        "district": "Сибирский",  
        "name": "Абакан",  
        "population": 187239,  
        "subject": "Хакасия"  
    }]  
  
  
# Создание схемы на основе датакласса  
CitySchema = marshmallow_dataclass.class_schema(City)  
  
# Расширяем своей схемой, схему созданную на основе датакласса  
  
class CoordsSchema(Schema):  
    lat = fields.Float()  
    lon = fields.Float()  
  
class CitySchemaExtended(CitySchema):  
    coords = fields.Nested(CoordsSchema, required=True)  
  
  
# Десериализация  
city_schema = CitySchemaExtended(many=True)  
cities = city_schema.load(cities_list)  
print(cities)  
  
# Сериализация  
result = city_schema.dump(cities)  
print(result)

Описание

Этот код демонстрирует процесс создания, сериализации и десериализации данных о городах, используя библиотеки dataclasses для определения структуры данных и marshmallow вместе с marshmallow_dataclass для обработки сериализации/десериализации и валидации данных.

Создание класса данных City

Сначала определяется класс City с использованием декоратора @dataclass. Класс включает поля: имя города, район, субъект, население, электронная почта и координаты. Для поля population задается валидация с помощью встроенного валидатора Range, который ограничивает значения от 1 до 1 000 000, обеспечивая, что население будет в этом диапазоне. Поле email задано как необязательное с пустым значением по умолчанию и помечено для использования только при загрузке данных (load_only=True), что означает, оно не будет включено при сериализации объектов обратно в JSON. Для coords используется фабрика по умолчанию для создания пустого словаря.

Подготовка данных для десериализации

Затем создается список словарей cities_list, который содержит данные о двух городах, включая их координаты, район, название, население и субъект. Эти данные предназначены для десериализации, то есть преобразования из формата JSON в объекты Python.

Автоматическое создание схемы с marshmallow_dataclass

С помощью функции class_schema из marshmallow_dataclass автоматически создается схема Marshmallow для класса City. Это упрощает процесс, поскольку не требуется вручную определять поля схемы и их валидацию.

Расширение автоматически созданной схемы

Для улучшения обработки координат создается дополнительная схема CoordsSchema и расширяется исходная схема CitySchema, заменяя поле coords на вложенную схему CoordsSchema с помощью fields.Nested. Это обеспечивает дополнительную валидацию координат, гарантируя, что они соответствуют ожидаемому формату с плавающей точкой.

Процесс десериализации и сериализации

  • Десериализация: Используя расширенную схему CitySchemaExtended, данные из cities_list преобразуются в список объектов City. Этот процесс включает в себя валидацию данных согласно определенным правилам и преобразование их в объекты Python.
  • Сериализация: Объекты City затем сериализуются обратно в формат JSON. В этом процессе поля email исключаются из результатов, так как они были помечены как load_only.

Вывод результатов

В конце, результаты десериализации и последующей сериализации выводятся на экран, показывая, как исходные данные были преобразованы в объекты и обратно в JSON.

В целом, этот код иллюстрирует мощные возможности сочетания dataclasses и marshmallow для обработки сложных структур данных с автоматической валидацией и удобным преобразованием между форматами объектов Python Python и JSON. Это особенно полезно при разработке API, где требуется эффективная обработка данных, приходящих в различных форматах, и их валидация согласно определенным правилам или ограничениям. Использование marshmallow_dataclass значительно упрощает этот процесс, позволяя разработчикам сосредоточиться на бизнес-логике приложения, вместо ручного определения и поддержки схем данных и валидационной логики.

Ключевые моменты, которые стоит заметить в этом процессе:

  • Автоматизация создания схем: marshmallow_dataclass автоматически создает схемы на основе датаклассов, значительно сокращая объем кода, необходимого для их ручного определения.
  • Валидация данных: Использование встроенных и кастомных валидаторов Marshmallow в metadata поля датакласса позволяет легко применять сложные правила валидации без дополнительного кода.
  • Гибкая кастомизация: Несмотря на автоматизацию, разработчики имеют возможность кастомизировать процесс сериализации/десериализации, расширяя автоматически сгенерированные схемы или добавляя дополнительные поля и валидаторы.
  • Управление сериализацией/десериализацией: Через метаданные можно указывать, какие поля должны быть включены или исключены из процесса, а также управлять поведением по умолчанию, например, задавая значения по умолчанию для отсутствующих данных.

Class Meta

Класс Meta внутри схемы Marshmallow используется для настройки поведения схемы в целом. Один из параметров, который можно определить внутри класса Meta, — это unknown. Этот параметр управляет тем, как схема должна обрабатывать неизвестные поля, то есть поля, которые присутствуют в ваших данных, но не определены в схеме.

unknown = INCLUDE

Когда вы устанавливаете unknown = INCLUDE в классе Meta вашей схемы, это указывает Marshmallow, что необходимо принимать и включать неизвестные поля в результат сериализации или десериализации. Это может быть полезно, когда вы работаете с динамическими данными, структура которых может меняться или содержать дополнительные поля, не критичные для вашей бизнес-логики.

Другие возможные значения для unknown:

  • EXCLUDE: Это значение говорит Marshmallow игнорировать неизвестные поля. Если входные данные содержат поля, которых нет в схеме, они будут просто игнорироваться и не включены в выходные данные. Это значение по умолчанию.
  • RAISE: Указывает Marshmallow генерировать ошибку при обнаружении неизвестных полей. Это полезно для сценариев, когда вы хотите строго контролировать структуру ваших данных и быть уверенным, что они соответствуют ожидаемому формату.

Другие параметры, которые можно указать в Meta:

  • fields: Список строк, определяющий, какие поля должны быть включены в сериализацию. Если определен, только поля, указанные в этом списке, будут обработаны.
  • additional: Список строк, определяющий дополнительные поля, которые следует включить в сериализацию наряду с теми, что уже определены в схеме.
  • load_only: Список полей, которые должны использоваться только для десериализации и не должны сериализоваться обратно в выходные данные.
  • dump_only: Список полей, которые должны использоваться только для сериализации и не учитываться при десериализации.
  • dateformat: Строка, определяющая формат даты, который будет использоваться для полей с датами при их сериализации.
  • ordered: Булево значение, указывающее, должны ли поля в выходных данных следовать в том порядке, в котором они определены в схеме.

Использование класса Meta предоставляет мощный инструмент для настройки поведения ваших схем Marshmallow, позволяя точно контролировать процесс сериализации и десериализации данных, обеспечивая гибкость и соответствие требованиям вашего приложения.