Может ли Alembic быть применен к существующей базе данных и пропустить создание / изменение таблиц / столбцов, если он обнаружит, что они уже существуют? - PullRequest
0 голосов
/ 31 октября 2019

Я создал несколько миграций, уже используя Alembic, это действительно интересный инструмент.

Использовать его на новой БД было бы достаточно просто, однако наш сценарий использования заключается в применении этих миграций к существующим БД, а нетолько для того, чтобы довести их «до скорости», но чтобы убедиться, что, например, если таблица или столбец будут изменены через интерфейс phpmyadmin или таблица уже существует, ее можно исправить / создать.

Это было бы прекрасно, поскольку созданный для этого сценария MigrationID мог бы быть применен к любой имеющейся у нас БД, исправляя любые несоответствия, не создавая дубликатов, пропуская то, что он считает правильным.

Как уже упоминалось, свежую базу данных, созданную с использованием Alembic, можно было бы исправить с помощью понижения версии и повторного применения, но мне интересно, можно ли это сделать с существующей БД, где Alembic применяется после.

Для справки, вот первый пример кода миграции, если он чем-то полезен.

"""create account table

Revision ID: bd4ec9e8afe8
Revises: 
Create Date: 2019-10-29 15:25:39.736234

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.mysql import TINYINT


# revision identifiers, used by Alembic.
revision = 'bd4ec9e8afe8'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():

    op.create_table(
        'account',
        sa.Column('id', sa.Integer, primary_key=True, nullable=False),
        sa.Column('title', sa.String(150), nullable=False),
        sa.Column('description', sa.Text, nullable=False),
        sa.Column('uploads_allowed', TINYINT(), nullable=True),
        sa.Column('viewers_contact_details', TINYINT(), default=0),
    )

    op.alter_column('account', sa.Column('id', sa.Integer, nullable=False, autoincrement=True))



    # op.execute("""
    # CREATE TABLE `account` (
    # `id` int(11) NOT NULL,
    # `title` varchar(150) NOT NULL,
    # `description` text,
    # `uploads_allowed` tinyint(1) DEFAULT '0',
    # `viewers_contact_details` tinyint(1) DEFAULT '0'
    # );
    # """)




def downgrade():
    op.drop_table('account')

Ответы [ 2 ]

1 голос
/ 01 ноября 2019

Поэтому моя проблема заключалась в том, что я не мог обнаружить изменения в БД, не используя if / else и try / кроме каждой отдельной миграции. Хотя это сработало, оно могло запутаться и полностью сломаться, если запрос, который я использовал для проверки БД, был неправильным или не вернул точно то, что ожидалось.

Решением было создание модели моегои используйте это как модель, из которой Alembic использует --autogenerate.

@ Supershoot указал мне на этот инструмент . Это создает модель того, на что вы указываете. Используя это, я смог изменить свой env.py следующим образом:

from logging.config import fileConfig

from sqlalchemy import engine_from_config
from sqlalchemy import pool

from alembic import context

import sys
from os.path import abspath, dirname
sys.path.insert(0, "/home/user/gitprojects/myproject/alembic/alembic/models")
import base


# this is the Alembic Config object, which provides
# access to the values within the# from myapp import mymodel
# target_metadata = mymodel.Base.metadata .ini file in use.
config = context.config# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
# Interpret the config file for P# from myapp import mymodel
# target_metadata = mymodel.Base.metadataython logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)

# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = base.Base.metadata
# target_metadata = None

Моя структура каталогов выглядит следующим образом:

├── alembic
│   ├── env_manualmig.py
│   ├── env.py
│   ├── models
│   │   ├── base.py
│   │   └── __pycache__
│   │       └── base.cpython-37.pyc
│   ├── __pycache__
│   │   └── env.cpython-37.pyc
│   ├── README
│   ├── script.py.mako
│   └── versions
│       ├── bd4ec9e8afe8_create_account_table.py
│       ├── f05b82b25f44_base.py
│       ├── fada1a35f790_add_a_column.py
│       └── __pycache__
│           ├── bd4ec9e8afe8_create_account_table.cpython-37.pyc
│           ├── f05b82b25f44_base.cpython-37.pyc
│           └── fada1a35f790_add_a_column.cpython-37.pyc
├── alembic.ini
├── Pipfile
├── Pipfile.lock
└── sa

Использование команды sqlacodegen mysql://u:p@host/name --outfile name_of_file.py

А затем: alembic revision --autogenerate -m "base" сгенерировал скрипт автоматической миграции после проверки правильности модели.

Затем он сравнил имеющиеся у него метаданные с базой данных, на которую он указывал, и правильно обнаружил отсутствующие или измененные столбцы. Тем не менее, мы настоятельно рекомендуем проверить правильность автоматически сгенерированной миграции, так как могут быть ошибки или другие несоответствия, которые алембик мог не заметить.

1 голос
/ 31 октября 2019

Вы можете создать новую ревизию, используя:

$ alembic revision -m "некоторое описание ревизии"

Затем будет создан файл ревизии с идентификатором.

Заполните функции обновления и понижения в соответствии с вашими изменениями, затем выполните следующую команду:

$ головка обновления alembic

Это внесет измененияв существующую базу данных.

...