Object-Relational Mapping, или ORM, – это техника программирования, которая позволяет разработчикам работать с базами данных, используя объектно-ориентированные принципы. С ORM вы можете манипулировать данными в базе данных, как если бы это были обычные объекты в вашем коде. Это устраняет необходимость писать громоздкие SQL-запросы вручную, делая код более читаемым и легким для сопровождения.
Представьте себе типичную задачу: вы хотите получить список пользователей из базы данных, отсортированный по имени. Без ORM вам пришлось бы писать что-то вроде этого:
SELECT * FROM users ORDER BY name;
А затем преобразовывать результат в объекты на языке программирования, таком как Python. С ORM этот процесс автоматизируется, и вы можете сделать это одной строкой кода:
users = session.query(User).order_by(User.name).all()
Зачем использовать ORM?
- Удобство и скорость разработки: ORM позволяет вам писать меньше кода и быстрее переходить от идеи к работающему приложению. Вам не нужно беспокоиться о написании и оптимизации SQL-запросов – ORM сделает это за вас.
- Поддерживаемость кода: Когда вы используете ORM, ваш код становится более читаемым и логичным. Вы работаете с объектами и методами, а не с сырыми SQL-запросами, что упрощает понимание и поддержку кода.
- Безопасность: ORM автоматически обрабатывает параметры запросов, что снижает риск SQL-инъекций – одной из самых распространенных уязвимостей в веб-приложениях.
- Кросс-база данных совместимость: С ORM вы можете легко переключаться между различными системами управления базами данных (например, MySQL, PostgreSQL, SQLite), практически не изменяя код приложения.
Установка и настройка
Как установить SQLAlchemy через pip
Установка SQLAlchemy очень проста и занимает всего несколько минут. SQLAlchemy распространяется через пакетный менеджер pip, что позволяет установить его одной командой в терминале:
pip install sqlalchemy
Если вы используете виртуальное окружение (virtual environment), убедитесь, что оно активировано перед установкой. Виртуальное окружение помогает изолировать зависимости проекта, что особенно полезно при работе над несколькими проектами с различными зависимостями.
Настройка базового окружения
После установки SQLAlchemy, необходимо настроить базовое окружение для работы с базой данных. Для этого создадим простой Python-скрипт. Пусть это будет файл main.py. В этом файле мы подключимся к базе данных и создадим сессию для взаимодействия с ней.
Импорт необходимых модулей:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base
Создание движка:
Движок (Engine) – это основной компонент SQLAlchemy, который отвечает за связь с базой данных. Мы будем использовать SQLite для простоты, но SQLAlchemy поддерживает множество других баз данных, таких как PostgreSQL, MySQL и др.
engine = create_engine('sqlite:///example.db')
Здесь мы создаем движок, который будет работать с файлом базы данных example.db. Если файл не существует, он будет создан автоматически.
Создание декларативной базы:
Декларативная база (Declarative Base) – это базовый класс для всех моделей, которые мы будем определять. Она предоставляет основные возможности для работы с таблицами и маппингом.
Base = declarative_base()
Создание сессии:
Сессия (Session) – это объект, который используется для всех операций с базой данных. Она является посредником между вашим кодом и движком.
Session = sessionmaker(bind=engine)
session = Session()
Теперь у нас есть базовая настройка, и мы готовы к созданию моделей и таблиц.
Подключение к базе данных
SQLAlchemy поддерживает множество различных баз данных. Вот несколько примеров строк подключения к различным базам данных:
PostgreSQL:
engine = create_engine('postgresql://username:password@localhost/mydatabase')
MySQL:
engine = create_engine('mysql+pymysql://username:password@localhost/mydatabase')
SQLite:
engine = create_engine('sqlite:///example.db')
Для каждой базы данных могут быть свои специфические настройки, такие как драйверы и параметры подключения, но основной принцип остается тем же.
Пример подключения и настройки
Создадим пример файла app.py, который демонстрирует все вышеперечисленные шаги:
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker, declarative_base
# Создание движка
engine = create_engine('sqlite:///example.db')
# Создание декларативной базы
Base = declarative_base()
# Определение модели
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
# Создание таблиц
Base.metadata.create_all(engine)
# Создание сессии
Session = sessionmaker(bind=engine)
session = Session()
# Добавление нового пользователя
new_user = User(name='John Doe')
session.add(new_user)
session.commit()
Основные концепции SQLAlchemy
В основе SQLAlchemy три компонента:
- Engine (движок): основной компонент SQLAlchemy, который управляет подключением к базе данных и выполняет SQL-запросы. Движок инкапсулирует всю информацию, необходимую для связи с базой данных, такую как URL подключения, драйвер базы данных и параметры конфигурации.
- Session (сессия): фабрика для создания новых объектов сессии, которые обеспечивают безопасное и управляемое взаимодействие с базой данных. Сессия используется для выполнения всех операций с базой данных, таких как добавление, обновление, удаление и запрос данных. Она также управляет транзакциями, что позволяет гарантировать целостность данных.
- Declarative Base (декларативная база): базовый класс, от которого наследуются все модели. Он предоставляет декларативный способ определения моделей и таблиц, что упрощает и делает код более читаемым.
Модели
Модели в SQLAlchemy представляют собой классы Python, которые определяют структуру таблиц базы данных и их взаимоотношения. Они позволяют работать с базой данных как с объектами Python, абстрагируя сложность SQL-запросов и предоставляя удобный интерфейс для манипуляции данными.
Основные аспекты моделей в SQLAlchemy:
- Определение структуры таблиц: Модели содержат информацию о столбцах таблицы, их типах и атрибутах. Каждый столбец в таблице базы данных представлен атрибутом класса модели.
- Отражение таблиц в базе данных: Модели используются для создания таблиц в базе данных или для отражения существующих таблиц. Это позволяет использовать ORM (Object-Relational Mapping) для работы с данными.
- Связи между таблицами: Модели могут определять отношения между таблицами, такие как один-к-одному, один-ко-многим и многие-ко-многим. Это упрощает работу с связанными данными.
- Удобное манипулирование данными: Использование моделей позволяет манипулировать данными в базе данных через объекты Python, что делает код более читаемым и понятным.
Создание моделей
Начнем с базовой настройки и затем создадим модели для пользователей (User) и адресов (Address).
Шаг 1: Импорт необходимых модулей
Импортируем модули из SQLAlchemy, которые понадобятся для создания моделей.
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Шаг 2: Создание базового класса для моделей
Создаем базовый класс, от которого будут наследоваться все наши модели. Этот класс предоставляется SQLAlchemy и используется для определения наших таблиц.
# Базовый класс для всех моделей
Base = declarative_base()
Шаг 3: Определение модели User
Создаем модель User, которая будет представлять таблицу users в базе данных.
# Определяем модель User
class User(Base):
__tablename__ = 'users' # Имя таблицы в базе данных
id = Column(Integer, primary_key=True, index=True) # Первичный ключ
name = Column(String, index=True) # Имя пользователя
email = Column(String, unique=True, index=True) # Уникальная электронная почта
age = Column(Integer) # Возраст пользователя
# Метод для удобного текстового представления объекта
def __repr__(self):
return f"<User(name={self.name}, email={self.email}, age={self.age})>"
Шаг 4: Определение модели Address
Создадим модель Address, которая будет хранить адреса пользователей и демонстрировать отношения между таблицами.
# Определяем модель Address
class Address(Base):
__tablename__ = 'addresses' # Имя таблицы в базе данных
id = Column(Integer, primary_key=True, index=True) # Первичный ключ
user_id = Column(Integer, ForeignKey('users.id')) # Внешний ключ, ссылающийся на таблицу users
address = Column(String, index=True) # Адрес пользователя
# Устанавливаем связь с моделью User
user = relationship('User', back_populates='addresses')
# Метод для удобного текстового представления объекта
def __repr__(self):
return f"<Address(user_id={self.user_id}, address={self.address})>"
Шаг 5: Установление связей в модели User
Чтобы завершить создание отношений, добавим обратную связь в модель User.
# Добавляем связь в модели User
User.addresses = relationship('Address', back_populates='user')
Типы колонок и их атрибутов
При создании моделей в SQLAlchemy мы используем различные типы колонок и атрибуты для их настройки. Давайте подробно рассмотрим, какие бывают типы колонок и атрибуты.
Типы колонок (Columns):
- Integer: целое число
- String: строка (текст)
- Float: число с плавающей точкой
- Boolean: логическое значение (True/False)
- Date: дата
- DateTime: дата и время
- Text: длинный текст
- Enum: перечисление
- ForeignKey: внешний ключ, связывающий с другой таблицей
Атрибуты колонок:
- primary_key: Указывает, что колонка является первичным ключом.
- unique: Указывает, что значения в колонке должны быть уникальными.
- index: Создает индекс для колонки, что ускоряет операции поиска.
- nullable: Указывает, может ли колонка содержать NULL значения.
- default: Устанавливает значение по умолчанию для колонки.
CRUD-операции
CRUD-операции (Create, Read, Update, Delete) — это основные действия, которые выполняются с данными в базе данных. Рассмотрим их на примере модели пользователя (User) в SQLAlchemy.
Create (Создание)
Для создания нового пользователя в базе данных мы будем использовать метод add() для добавления нового объекта в сессию и метод commit() для сохранения изменений в базе данных.
def create_user(db_session, name, email, age):
# Создаем экземпляр модели User
new_user = User(name=name, email=email, age=age)
db_session.add(new_user) # Добавляем пользователя в сессию
db_session.commit() # Фиксируем изменения в базе данных
db_session.refresh(new_user) # Обновляем объект, чтобы получить присвоенный id
return new_user
# Пример использования
db = SessionLocal()
user = create_user(db, name="Alice", email="alice@example.com", age=25)
print(user)
db.close()
Read (Чтение)
Для чтения данных мы используем метод query(). Рассмотрим несколько способов получения данных.
def get_user_by_id(db_session, user_id):
return db_session.query(User).filter(User.id == user_id).first()
def get_user_by_email(db_session, email):
return db_session.query(User).filter(User.email == email).first()
def get_all_users(db_session):
return db_session.query(User).all()
# Пример использования
db = SessionLocal()
user = get_user_by_id(db, user_id=1)
print(user)
user = get_user_by_email(db, email="alice@example.com")
print(user)
users = get_all_users(db)
print(users)
db.close()
Update (Обновление)
Для обновления данных мы сначала получаем объект, изменяем его атрибуты, затем фиксируем изменения в базе данных с помощью метода commit().
def update_user(db_session, user_id, name=None, email=None, age=None):
user = db_session.query(User).filter(User.id == user_id).first()
if user:
if name:
user.name = name
if email:
user.email = email
if age is not None:
user.age = age
db_session.commit() # Фиксируем изменения в базе данных
db_session.refresh(user) # Обновляем объект
return user
# Пример использования
db = SessionLocal()
user = update_user(db, user_id=1, name="Alice Smith", age=26)
print(user)
db.close()
Delete (Удаление)
Для удаления данных мы получаем объект, удаляем его из сессии с помощью метода delete() и фиксируем изменения в базе данных с помощью метода commit()
def delete_user(db_session, user_id):
user = db_session.query(User).filter(User.id == user_id).first()
if user:
db_session.delete(user) # Удаляем пользователя из сессии
db_session.commit() # Фиксируем изменения в базе данных
return user
# Пример использования
db = SessionLocal()
user = delete_user(db, user_id=1)
print(user)
db.close()