Alembic миграции
Для инициализации данных в таблицах базы данных PostgreSQL с использованием SQLAlchemy и Alembic, рекомендуется использовать Alembic миграции. Это позволит создавать начальные данные в таблице при выполнении миграций.
Вот пошаговый подход для добавления первых данных в таблицу:
1. Создайте миграцию с Alembic
Используйте команду alembic revision --autogenerate -m "Добавление начальных данных" или создайте новую миграцию вручную:
alembic revision -m "Добавление начальных данных"
2. Добавьте код для вставки данных в миграцию
В созданном файле миграции найдите функцию upgrade и добавьте SQL-запросы или ORM-операции для вставки данных.
Пример файла миграции (<timestamp>_добавление_начальных_данных.py):
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '<revision_id>'
down_revision = '<previous_revision_id>'
branch_labels = None
depends_on = None
def upgrade():
# Добавление начальных данных
conn = op.get_bind()
conn.execute(
sa.text(
"INSERT INTO settings (key, value) VALUES (:key, :value) ON CONFLICT (key) DO NOTHING"
),
[{"key": "is_mode_get_user_id", "value": "0"},
{"key": "get_user_id_message", "value": "😶😶😶"}]
)
def downgrade():
# Удаление данных (опционально, если требуется при откате)
conn = op.get_bind()
conn.execute(
sa.text("DELETE FROM settings WHERE key IN (:keys)"),
{"keys": ("is_mode_get_user_id", "get_user_id_message")}
)
3. Обновите базу данных с помощью Alembic
Примените новую миграцию, выполнив:
Пояснение:
conn = op.get_bind(): Получает соединение с базой данных для выполнения SQL-запросов напрямую.ON CONFLICT (key) DO NOTHING: PostgreSQL-конструкция для игнорирования ошибок вставки, если запись с таким ключом уже существует (аналогичноINSERT OR IGNOREв SQLite).- Использование
sa.text: Позволяет вставлять данные через сырые SQL-запросы с поддержкой параметров.
Альтернативный подход через ORM (опционально)
Если вы хотите использовать SQLAlchemy ORM вместо сырых SQL-запросов, можно выполнить инициализацию в отдельном скрипте, используя сессию:
from sqlalchemy.orm import Session
from your_project.models import Setting # Импортируйте вашу ORM-модель
def initialize_settings(engine):
with Session(engine) as session:
# Проверяем, есть ли записи, и добавляем только если они отсутствуют
if not session.query(Setting).filter(Setting.key == "is_mode_get_user_id").first():
session.add(Setting(key="is_mode_get_user_id", value="0"))
if not session.query(Setting).filter(Setting.key == "get_user_id_message").first():
session.add(Setting(key="get_user_id_message", value="😶😶😶"))
session.commit()Рекомендации:
- Для разового выполнения начальной инициализации используйте Alembic миграции.
- Если данные должны проверяться и обновляться динамически, создайте отдельную функцию для инициализации, как в примере с ORM.
Использовать Alembic или ORM для внесения начальных данных возможно, и оба подхода имеют свои плюсы. Вот детальное руководство для обоих случаев.
1. Внесение данных через Alembic
В миграциях Alembic вы можете использовать SQLAlchemy ORM для работы с таблицами.
Пример файла миграции (<timestamp>_добавление_данных.py):
from alembic import op
from sqlalchemy.orm import Session
from sqlalchemy import inspect
from your_project.models import Settings # Импортируйте вашу модель Settings
# revision identifiers, used by Alembic.
revision = '<revision_id>'
down_revision = '<previous_revision_id>'
branch_labels = None
depends_on = None
def upgrade():
# Получение текущей сессии
bind = op.get_bind()
session = Session(bind=bind)
# Проверка существования таблицы (опционально)
inspector = inspect(bind)
if 'settings' in inspector.get_table_names():
# Вставка данных, если таблица существует
settings = [
Settings(key='is_mode_get_user_id', value='0'),
Settings(key='get_user_id_message', value='😶😶😶'),
]
for setting in settings:
# Убедитесь, что данные добавляются только при отсутствии
if not session.query(Settings).filter_by(key=setting.key).first():
session.add(setting)
session.commit()
def downgrade():
# Откат: удаление данных
bind = op.get_bind()
session = Session(bind=bind)
session.query(Settings).filter(
Settings.key.in_(['is_mode_get_user_id', 'get_user_id_message'])
).delete(synchronize_session=False)
session.commit() Пояснения:
Session(bind=bind): Создаёт сессию на основе текущего соединения Alembic.- Проверка на существование таблицы: Это полезно, если вы не уверены, что таблица уже создана.
- Проверка существующих записей: Гарантирует, что данные не будут добавлены повторно, если миграция выполняется несколько раз.
2. Внесение данных через ORM
Этот метод подходит, если вы хотите вставить данные в таблицу в вашем основном коде приложения.
Пример:
from sqlalchemy.orm import Session
from your_project.models import Settings
from sqlalchemy import create_engine
from your_project.database import Base # где инициализируется ваш Base
# Создаём подключение к базе данных
engine = create_engine("postgresql+psycopg2://username:password@localhost/dbname")
def initialize_settings():
with Session(engine) as session:
# Добавляем данные, если они ещё не существуют
if not session.query(Settings).filter_by(key="is_mode_get_user_id").first():
session.add(Settings(key="is_mode_get_user_id", value="0"))
if not session.query(Settings).filter_by(key="get_user_id_message").first():
session.add(Settings(key="get_user_id_message", value="😶😶😶"))
session.
# Вызываем функцию инициализации
if __name__ == "__main__":
initialize_settings()Что выбрать?
- Alembic миграции: Если данные должны быть добавлены вместе с обновлением структуры базы данных. Это лучший подход для контроля версий.
- ORM: Если данные должны добавляться в рантайме, например, при первом запуске приложения.
Комбинированный подход:
Если вы используете Alembic для структуры таблиц, но хотите более гибкий способ добавления данных, используйте Alembic с ORM в одном из миграционных скриптов, как показано в первом примере.