← Назад к вопросам
Как взаимодействовать с реляционными базами данных?
1.7 Middle🔥 211 комментариев
#Python Core#Базы данных (SQL)
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Работа с реляционными базами данных в Python
В Python существует несколько подходов для взаимодействия с БД. Выбор зависит от сложности проекта и требований.
1. DB-API (Низкоуровневый доступ)
Стандартный интерфейс для взаимодействия с БД. Каждая БД имеет свой драйвер:
# PostgreSQL
import psycopg2
connection = psycopg2.connect(
dbname="mydb",
user="postgres",
password="secret",
host="localhost",
port=5432
)
cursor = connection.cursor()
# SELECT
cursor.execute("SELECT * FROM users WHERE age > %s", (18,))
users = cursor.fetchall()
for user in users:
print(user)
# INSERT
cursor.execute(
"INSERT INTO users (name, email, age) VALUES (%s, %s, %s)",
("John", "john@example.com", 25)
)
connection.commit()
# UPDATE
cursor.execute("UPDATE users SET age = %s WHERE name = %s", (26, "John"))
connection.commit()
# DELETE
cursor.execute("DELETE FROM users WHERE age < %s", (18,))
connection.commit()
cursor.close()
connection.close()
Другие драйверы БД
# MySQL
import mysql.connector
connection = mysql.connector.connect(
host="localhost",
user="root",
password="password",
database="mydb"
)
# SQLite (встроенная БД)
import sqlite3
connection = sqlite3.connect("database.db")
# SQL Server
import pyodbc
connection = pyodbc.connect(
"Driver={ODBC Driver 17 for SQL Server};Server=server;Database=db;UID=user;PWD=pass"
)
2. SQLAlchemy ORM (Высокоуровневый подход)
Объектно-реляционное отображение. Абстрагирует конкретную БД.
from sqlalchemy import create_engine, Column, Integer, String, DateTime
from sqlalchemy.orm import declarative_base, sessionmaker
from datetime import datetime
# Создание engine
engine = create_engine("postgresql://user:password@localhost/mydb")
Base = declarative_base()
# Определение модели
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
name = Column(String(50), nullable=False)
email = Column(String(100), unique=True)
age = Column(Integer)
created_at = Column(DateTime, default=datetime.utcnow)
# Создание таблиц
Base.metadata.create_all(engine)
# Создание сессии
Session = sessionmaker(bind=engine)
session = Session()
# CREATE
new_user = User(name="John", email="john@example.com", age=25)
session.add(new_user)
session.commit()
# READ
users = session.query(User).filter(User.age > 18).all()
for user in users:
print(user.name, user.email)
# UPDATE
user = session.query(User).filter_by(name="John").first()
if user:
user.age = 26
session.commit()
# DELETE
user = session.query(User).filter_by(name="John").first()
if user:
session.delete(user)
session.commit()
session.close()
3. SQLAlchemy Core (Средний уровень)
Чистый SQL с удобством Python:
from sqlalchemy import create_engine, select, insert, update, delete, Table, Column, Integer, String, MetaData
engine = create_engine("postgresql://user:password@localhost/mydb")
metadata = MetaData()
users_table = Table(
"users",
metadata,
Column("id", Integer, primary_key=True),
Column("name", String(50)),
Column("email", String(100)),
Column("age", Integer)
)
with engine.connect() as conn:
# SELECT
stmt = select(users_table).where(users_table.c.age > 18)
result = conn.execute(stmt)
for row in result:
print(row)
# INSERT
stmt = insert(users_table).values(name="John", email="john@example.com", age=25)
conn.execute(stmt)
conn.commit()
# UPDATE
stmt = update(users_table).where(users_table.c.name == "John").values(age=26)
conn.execute(stmt)
conn.commit()
# DELETE
stmt = delete(users_table).where(users_table.c.age < 18)
conn.execute(stmt)
conn.commit()
4. Работа с миграциями (Alembic)
Управление изменениями схемы БД:
# Инициализация
alembic init migrations
# Создание миграции
alembic revision --autogenerate -m "Add age column to users"
# Применение миграции
alembic upgrade head
# Откат миграции
alembic downgrade -1
# Пример миграции (migrations/versions/001_initial.py)
from alembic import op
import sqlalchemy as sa
def upgrade():
op.create_table(
"users",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("name", sa.String(50), nullable=False),
sa.Column("email", sa.String(100), nullable=True),
sa.PrimaryKeyConstraint("id")
)
def downgrade():
op.drop_table("users")
5. Управление соединениями (Connection Pooling)
from sqlalchemy import create_engine
from sqlalchemy.pool import QueuePool
engine = create_engine(
"postgresql://user:password@localhost/mydb",
poolclass=QueuePool,
pool_size=5, # Минимум соединений в пуле
max_overflow=10, # Максимум дополнительных соединений
pool_recycle=3600, # Переиспользовать соединение через 1 час
pool_pre_ping=True # Проверять соединение перед использованием
)
6. Контекстный менеджер для безопасной работы
from contextlib import contextmanager
@contextmanager
def get_db_connection(connection_string):
"""Безопасное управление соединением"""
connection = None
try:
connection = psycopg2.connect(connection_string)
yield connection
except Exception as e:
print(f"Database error: {e}")
if connection:
connection.rollback()
finally:
if connection:
connection.close()
# Использование
with get_db_connection("dbname=mydb user=postgres") as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM users")
users = cursor.fetchall()
7. Транзакции и откаты
from sqlalchemy.orm import Session
session = Session(engine)
try:
# Несколько операций в одной транзакции
user1 = User(name="John", email="john@example.com", age=25)
user2 = User(name="Jane", email="jane@example.com", age=28)
session.add(user1)
session.add(user2)
session.commit() # Всё успешно
except Exception as e:
session.rollback() # Откат всех изменений
print(f"Transaction failed: {e}")
finally:
session.close()
8. Защита от SQL Injection
Всегда используй параметризованные запросы:
# ❌ ПЛОХО - уязвимо для SQL Injection
query = f"SELECT * FROM users WHERE email = {user_email}"
cursor.execute(query)
# ✅ ХОРОШО - защищено
cursor.execute("SELECT * FROM users WHERE email = %s", (user_email,))
# SQLAlchemy защищает автоматически
user = session.query(User).filter_by(email=user_email).first()
9. Оптимизация запросов
from sqlalchemy import joinedload
# N+1 проблема
users = session.query(User).all()
for user in users:
print(user.posts) # Дополнительный запрос для каждого пользователя
# Решение: eager loading
users = session.query(User).options(joinedload(User.posts)).all()
# Batch loading
from sqlalchemy.orm import contains_eager
users = session.query(User).join(Post).options(contains_eager(User.posts)).all()
10. Лучшие практики
- Используй ORM для бизнес-логики
- Используй Raw SQL только для сложных/специфических запросов
- Всегда управляй соединениями (используй context managers)
- Защищай от SQL Injection (параметризованные запросы)
- Оптимизируй N+1 проблемы (eager loading)
- Настраивай connection pooling для production
- Тестируй все БД операции
Выбор подхода зависит от сложности проекта, но в большинстве случаев SQLAlchemy ORM — лучший выбор для Python приложений.