Мы уже говорили, что у 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 операций.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ