JavaRush /Курсы /Модуль 4: FastAPI /Определение полей и типов данных в моделях SQLAlchemy

Определение полей и типов данных в моделях SQLAlchemy

Модуль 4: FastAPI
6 уровень , 3 лекция
Открыта

Мы уже говорили, что у SQLAlchemy есть очень много встроенных типов данных, которые соотносятся с типами данных в SQL. Эти типы определяют, как именно ваши данные будут храниться в базе данных. Например, строки, целые числа, даты и времена, булевы значения и даже сложные объекты, такие как JSON.


Основные типы данных

Давайте рассмотрим табличку с основными типами данных и сразу постараемся применить на практике некоторые из них.

Тип SQLAlchemy Описание
String(size) Строковое поле, где size задаёт максимальную длину
Text Неограниченное текстовое поле
Integer Целое число
Float Число с плавающей точкой
Boolean Булево значение True/False
Date Дата (без времени)
DateTime Дата и время
JSON Поле для хранения JSON-объектов
LargeBinary Для хранения двоичных данных (например, изображений)
Enum Поле для перечислений (enums), например, "Активен/Неактивен"

А вот и пример использования. Можете попробовать расширить его или создать свой собственный.


from sqlalchemy import Column, Integer, String, Date, Boolean

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    name = Column(String(50))  # Максимальная длина 50 символов
    email = Column(String(120), unique=True, nullable=False)  # Уникальный и обязательный
    birth_date = Column(Date)  # Поле для даты рождения
    is_active = Column(Boolean, default=True)  # Флаг активности пользователя

Вот так просто, мы описали модель User с основными типами данных. Теперь давайте разберем детали, добавим немного магии и посмотрим, как работать с ограничениями и валидацией.


Пример расширенного определения модели

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

Сложная модель:


from sqlalchemy import Column, Integer, Float, DateTime, String, ForeignKey, Boolean
from sqlalchemy.orm import relationship
import datetime

class Product(Base):
    __tablename__ = "product"
    id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False)  # Название продукта
    price = Column(Float, nullable=False)  # Цена продукта
    created_at = Column(DateTime, default=datetime.datetime.utcnow)  # Время создания
    is_available = Column(Boolean, default=True)  # Флаг наличия товара

    # Связь с таблицей категорий
    category_id = Column(Integer, ForeignKey('category.id'))
    category = relationship("Category", back_populates="products")

class Category(Base):
    __tablename__ = "category"
    id = Column(Integer, primary_key=True)
    name = Column(String(50), unique=True, nullable=False)  # Название категории
    products = relationship("Product", back_populates="category")  # Связь с продуктами

Здесь мы используем:

  • Внешний ключ ForeignKey для связи продуктов с категориями.
  • Отношения через relationship, чтобы создать ассоциацию между двумя таблицами.
  • Поля с ограничениями, такими как уникальность (unique=True) и обязательность (nullable=False).

Валидация и ограничения

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

Уникальность:


email = Column(String(120), unique=True)

Теперь никто не сможет зарегистрировать два аккаунта с одним email-адресом.

Ограничения длины:


username = Column(String(20), nullable=False)

Здесь мы ограничили длину имени пользователя до 20 символов и сделали поле обязательным.

Для ускорения запросов можно добавить индексы:


surname = Column(String(50), index=True)

Выражения по умолчанию:


created_at = Column(DateTime, default=datetime.datetime.utcnow)

а теперь давайте используем всё вместе:


from sqlalchemy import Column, Integer, String, Float, DateTime, CheckConstraint

class Order(Base):
    __tablename__ = 'order'
    id = Column(Integer, primary_key=True)
    product_id = Column(Integer, nullable=False)
    quantity = Column(Integer, CheckConstraint('quantity > 0'), nullable=False)  # Количество должно быть > 0
    total_price = Column(Float, nullable=False)
    created_at = Column(DateTime, default=datetime.datetime.utcnow)

Пользовательские типы данных

Иногда нужно создать свой собственный тип данных. Например, вы хотите добавить тип для хранения "цвета" в формате HEX.

Реализация пользовательского типа:


from sqlalchemy.types import TypeDecorator, String

class ColorType(TypeDecorator):
    impl = String

    def process_bind_param(self, value, dialect):
        if not value.startswith("#"):
            raise ValueError("Цвет должен быть в формате HEX, начинаться с #.")
        return value

    def process_result_value(self, value, dialect):
        return value.upper()  # Всегда возвращать цвет в верхнем регистре

Использование в модели:


class Theme(Base):
    __tablename__ = 'theme'
    id = Column(Integer, primary_key=True)
    name = Column(String(50), nullable=False)
    primary_color = Column(ColorType, nullable=False)  # Поле для цвета

Таким образом, вы можете добавлять любое поведение к своим типам данных.


Важно знать: типичные ошибки

В процессе работы со схемами и типами данных можно нарваться на неприятности. Например:

  • Ошибка согласования типов: если вы пытаетесь использовать строку в поле, ожидающем Integer, то получите исключение. Всегда проверяйте соответствие типов в вашей модели и данных.
  • Уникальные ограничения: добавляя unique=True, учтите, что в базе данных тоже должен быть индекс для этого. SQLAlchemy делает это автоматически, но если вы забыли, индексация будет медленной.
  • Ограничения NOT NULL: если поле помечено как nullable=False, а вы не передадите значение, то запрос завершится ошибкой.

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

1
Задача
Модуль 4: FastAPI, 6 уровень, 3 лекция
Недоступна
Создание модели с основными типами данных
Создание модели с основными типами данных
1
Задача
Модуль 4: FastAPI, 6 уровень, 3 лекция
Недоступна
Создание связанной модели
Создание связанной модели
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ