Базы данных в Python: драйверы, SQL и ORM

Раздел: Базы данных -> Общие вопросы по БД

Основные подходы к работе с базами данных в Python

Как унифицировать работу с разными СУБД и упростить разработку?

SQLAlchemy - наиболее эффективное решение для сложных проектов

SQLAlchemy предоставляет два уровня работы: Core (низкоуровневый SQL-конструктор) и ORM (объектно-реляционное отображение). Это позволяет писать код, независимый от конкретной базы данных, и сочетать гибкость SQL с удобством работы с объектами Python.


from sqlalchemy import create_engine, text

engine = create_engine('sqlite:///example.db')
with engine.connect() as conn:
    result = conn.execute(text("SELECT 'Привет, мир'"))
    print(result.fetchone()[0])
    

базы данных в python (базы данных в python)

Привет, мир
    

Пояснение: create_engine создаёт точку подключения. Строка подключения 'sqlite:///example.db' указывает на файл SQLite. Для PostgreSQL строка будет 'postgresql://user:pass@localhost/db'. Метод connect() возвращает контекстный менеджер, обеспечивающий автоматическое закрытие соединения.

Типичные проблемы:

  • Ошибка импорта: если не установлен пакет sqlalchemy - используйте pip install sqlalchemy.
  • Неверная строка подключения: синтаксис может различаться. Например, для MySQL требуется 'mysql+pymysql://...'.
  • Конфликты сессий: при использовании ORM следует правильно настроить SessionLocal и применять паттерн единой сессии на запрос.

Как выполнять простые операции без ORM?

Вариант 1: Встроенный модуль sqlite3

Подходит для локальных приложений, прототипов и тестов. Не требует установки дополнительных пакетов.


import sqlite3

conn = sqlite3.connect(':memory:')
cursor = conn.cursor()
cursor.execute('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)')
cursor.execute('INSERT INTO users VALUES (?, ?)', (1, 'Анна'))
conn.commit()
print(cursor.lastrowid)
1

Пояснение: sqlite3.connect(':memory:') создаёт базу в оперативной памяти. Плейсхолдеры ? защищают от SQL-инъекций. После изменения данных обязателен commit().

Ошибки:

  • Забытый commit - данные не сохраняются.
  • Закрытие соединения без commit - изменения теряются.
  • Неоднократное открытие одного файла - возможны блокировки.

Как подключиться к PostgreSQL из Python?

Вариант 2: Драйвер psycopg2

Рекомендуется для продакшен-систем на PostgreSQL. Устанавливается через pip install psycopg2-binary.


import psycopg2

conn = psycopg2.connect(
    host='localhost',
    port=5432,
    dbname='testdb',
    user='postgres',
    password='secret'
)
cur = conn.cursor()
cur.execute('SELECT version()')
print(cur.fetchone())
('PostgreSQL 15.4 (Debian 15.4-1.pgdg120+1) on x86_64-pc-linux-gnu',)

Пояснение: psycopg2.connect принимает параметры подключения. После работы нужно закрыть курсор и соединение, либо использовать контекстный менеджер.

Проблемы:

  • Неверный пароль/хост - OperationalError: could not connect to server.
  • Отсутствие библиотеки libpq - при установке psycopg2 (не binary) требуется компиляция. Используйте psycopg2-binary для простоты.
  • Утечка соединений - всегда закрывайте соединение, лучше через with conn:.

Как работать с MySQL?

Вариант 3: Драйвер mysql-connector-python

Официальный коннектор от Oracle. Установка: pip install mysql-connector-python.


import mysql.connector

conn = mysql.connector.connect(
    host='127.0.0.1',
    user='root',
    password='pass',
    database='mydb'
)
cursor = conn.cursor()
cursor.execute('SELECT NOW()')
print(cursor.fetchone())
(datetime.datetime(2025, 3, 21, 14, 55, 30),)

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

Частые ошибки:

  • Authentication plugin 'caching_sha2_password' - добавьте auth_plugin='mysql_native_password'.
  • Не найден database - проверьте имя базы.
  • Закрытие соединения - используйте conn.close() или менеджер контекста.
Пример

# Пример 1. SQLAlchemy ORM: связи между таблицами и транзакции
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship

engine = create_engine('sqlite:///university.db', echo=True)
Base = declarative_base()

class Student(Base):
    __tablename__ = 'students'
    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    group_id = Column(Integer, ForeignKey('groups.id'))
    group = relationship('Group', back_populates='students')

class Group(Base):
    __tablename__ = 'groups'
    id = Column(Integer, primary_key=True)
    name = Column(String(30))
    students = relationship('Student', back_populates='group')

Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine)
session = Session()

# Добавление объектов в транзакции
group = Group(name='CS-101')
student = Student(name='Иван Петров', group=group)
session.add(group)
session.add(student)
session.commit()

# Запрос с join
result = session.query(Student).join(Group).filter(Group.name == 'CS-101').all()
for s in result:
    print(f"Студент {s.name} из группы {s.group.name}")

session.close()
Студент Иван Петров из группы CS-101
Пример

# Пример 2. psycopg2: использование пула соединений
from psycopg2 import pool

connection_pool = pool.SimpleConnectionPool(
    2, 10,  # min, max connections
    host='localhost',
    dbname='postgres',
    user='postgres',
    password='pass'
)

conn = connection_pool.getconn()
try:
    cur = conn.cursor()
    cur.execute('SELECT count(*) FROM pg_stat_activity')
    print('Активные соединения:', cur.fetchone()[0])
finally:
    connection_pool.putconn(conn)

# Закрытие пула при завершении приложения
# connection_pool.closeall()
Активные соединения: 3
Пример

# Пример 3. sqlite3: работа со встроенными функциями
import sqlite3

conn = sqlite3.connect(':memory:')
conn.execute('CREATE TABLE items (id, price)')
conn.execute('INSERT INTO items VALUES (1, 250)')
conn.execute('INSERT INTO items VALUES (2, 450)')

# Создание пользовательской функции
conn.create_function('format_price', 1, lambda x: f"{x:.2f} руб")

cur = conn.execute('SELECT format_price(price) FROM items')
for row in cur:
    print(row[0])
250.00 руб
450.00 руб

Базы данных в Python - comments

En
базы данных в python (python)