Поиск по сайту:

Как выполнить миграцию Flask-SQLAlchemy с помощью Flask-Migrate


Автор выбрал Apache Software Foundation для получения пожертвования в рамках программы Write for DOnations.

Введение

Flask — это легкая веб-инфраструктура Python, предоставляющая ценные инструменты и функции для создания веб-приложений на языке Python. SQLAlchemy — это набор инструментов SQL, предлагающий эффективный и высокопроизводительный доступ к реляционной базе данных. Он предоставляет способы взаимодействия с несколькими ядрами баз данных, такими как SQLite, MySQL и PostgreSQL. Это дает вам доступ к функциям SQL базы данных. Он также предоставляет вам реляционный преобразователь объектов (ORM), который позволяет вам делать запросы и обрабатывать данные, используя простые объекты и методы Python. Flask-SQLAlchemy — это расширение Flask, которое упрощает использование SQLAlchemy с Flask, предоставляя вам инструменты и методы для взаимодействия с вашей базой данных в приложениях Flask через SQLAlchemy.

Flask-Migrate — это расширение Flask, основанное на библиотеке Alembic, позволяющее управлять миграцией баз данных.

Миграция базы данных — это перенос данных между различными схемами базы данных без потери данных. Он обычно используется для обновления базы данных, изменения ее схемы путем добавления новых столбцов или связей таблицы, а также для обеспечения плавного перехода с минимальным временем простоя и без потери данных.

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

В этом руководстве вы будете использовать Flask-Migrate с Flask-SQLAlchemy для выполнения миграции схемы базы данных для изменения таблиц и сохранения данных.

Предварительные условия

  • Для локальной среды программирования Python 3 следуйте инструкциям для вашего дистрибутива из серии «Как установить и настроить локальную среду программирования для Python 3». В этом уроке мы назовем каталог нашего проекта flask_app.

  • Понимание основных концепций Flask, таких как маршруты, функции просмотра и шаблоны. Если вы не знакомы с Flask, ознакомьтесь со статьями «Как создать свое первое веб-приложение с помощью Flask и Python» и «Как использовать шаблоны в приложении Flask».

  • Понимание основных концепций HTML. Просмотрите нашу серию руководств «Как создать веб-сайт с помощью HTML».

  • Понять основные концепции Flask-SQLAlchemy, такие как настройка базы данных, создание моделей базы данных и вставка данных в базу данных. Дополнительную информацию см. в разделе «Как использовать Flask-SQLAlchemy для взаимодействия с базами данных в приложении Flask».

Шаг 01. Установка необходимых пакетов Python

На этом этапе вы установите необходимые пакеты для вашего приложения.

В каталоге flask_app активируйте виртуальную среду:

source <my_env>/bin/activate

Активировав виртуальную среду, используйте pip для установки Flask, Flask-SQLAlchemy и Flask-Migrate:

pip install Flask Flask-SQLAlchemy Flask-Migrate

После завершения установки в результатах будет выведена строка, подобная следующей:

Successfully installed Flask-3.0.0 Flask-Migrate-4.0.5 Flask-SQLAlchemy-3.1.1 Jinja2-3.1.2 Mako-1.3.0 MarkupSafe-2.1.3 Werkzeug-3.0.1 alembic-1.12.1 blinker-1.7.0 click-8.1.7 greenlet-3.0.1 itsdangerous-2.1.2 sqlalchemy-2.0.23 typing-extensions-4.8.0

Установив необходимые пакеты Python, вы затем настроите пример базы данных и модели.

Шаг 02. Настройка примера базы данных и модели

На этом этапе вы настроите приложение Flask и базу данных Flask-SQLAlchemy с моделью, представляющей таблицу продуктов, в которой вы будете хранить продукты вашего магазина.

В каталоге flask_app откройте новый файл с именем app.py.. Он будет содержать основной код вашего приложения Flask:

nano app.py

Добавьте в него следующий код:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///app.db"
db = SQLAlchemy(app)


class Product(db.Model):
    __tablename__ = "products"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    def __repr__(self):
        return f"<Product {self.name}>"
@app.route("/")
def index():
    return "<h1>Hello, World!</h1>"

Сохраните и закройте файл.

Здесь вы импортируете класс Flask и SQLAlchemy из модулей flask и flask_sqlalchemy. Затем вы создаете экземпляр приложения Flask с именем app.

Затем вы устанавливаете URI базы данных SQLite в конфигурации приложения; это указывает имя файла базы данных как app.db. Этот файл базы данных будет создан в новой папке с именем instance, которая будет создана Flask в основном каталоге flask_app.

В db=SQLAlchemy(app), вы создаете экземпляр SQLAlchemy, db,, минуя приложение Flask в качестве аргумента.

Затем вы создаете класс Product, который наследуется от db.Model и представляет таблицу базы данных с именем «products». В таблице вы определяете столбец id для идентификатора продукта и столбец name для названия продукта.

Специальная функция repr позволяет вам присвоить каждому объекту строковое представление, чтобы распознать его в целях отладки.

Наконец, вы создаете маршрут ('/'), который возвращает простой HTML-ответ ("

Hello, World!

"), когда корневой URL-адрес доступен.

Выполните следующую команду, чтобы проверить правильность настройки приложения. Это запустит приложение app Flask на сервере разработки с активированной отладкой:

flask --app app run --debug

После запуска этой команды вы получите следующий вывод:

 * Serving Flask app 'app'
 * Debug mode: on
WARNING: This is a development server. Please do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 633-501-683

Это дает вам информацию о вашем приложении во время его работы.

При работающем сервере разработки посетите следующий URL-адрес в браузере:

http://127.0.0.1:5000/

Вы получите заголовок <h1> «Привет, мир!». Это подтверждает, что приложение настроено правильно. Теперь вы можете перейти к следующему шагу и добавить Flask-Migrate в свое приложение.

Шаг 03. Добавление Flask-Migrate в ваше приложение

На этом этапе вы измените файл приложения app.py, добавив Flask-Migrate и используя его для управления базой данных Flask-SQLAlchemy.

Сначала откройте app.py для внесения изменений:

nano app.py

Измените файл так, чтобы все, что находится над объявлением класса Product, выглядело следующим образом:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
db = SQLAlchemy(app)
migrate = Migrate(app, db)
class Product(db.Model):

Сохраните и закройте файл.

Вы импортируете класс Migrate из пакета flask_migrate.

После объявления db вы используете класс Migrate, чтобы инициировать экземпляр миграции под названием migrate, передавая его в приложение Flask. и экземпляр базы данных db.

Flask-Migrate предоставляет помощник команды flask db для управления вашей базой данных.

Чтобы завершить настройку Flask-Migrate и добавить поддержку в текущий проект, используйте следующую команду в каталоге flask_app:

flask db init

Вы получите вывод, аналогичный следующему:

[secondary_label Output]  
Creating directory 'flask_app/migrations' ...  done
  Creating directory 'flask_app/migrations/versions' ...  done
  Generating flask_app/migrations/README ...  done
  Generating flask_app/migrations/script.py.mako ...  done.
  Generating flask_app/migrations/env.py ...  done
  Generating flask_app/migrations/alembic.ini ...  done
  Please edit the configuration/connection/logging settings in
  'flask_app/migrations/alembic.ini' before proceeding.

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

Если вы знакомы с Alembic и хотите добавить расширенные конфигурации в свою систему миграции базы данных, вы можете изменить сгенерированный файл migrations/alembic.ini. Для наших целей оставим все как есть.

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

Подключив Flask-Migrate к вашему приложению, вы выполните первоначальную миграцию базы данных. Использование класса «Продукт» создаст таблицу продуктов, которую вы объявили ранее.

Создание таблицы продуктов с помощью сценария миграции

Теперь вы выполните первую миграцию, создав таблицу Products вашей базы данных.

В каталоге flask_app выполните следующую команду. Эта команда flask dbmigrate обнаруживает все новые таблицы или изменения, которые вы выполняете в моделях базы данных Flask-SQLAlchemy. Флаг -m позволяет вам указать короткое сообщение, описывающее выполненное вами изменение:

flask db migrate -m "initial migration"

Вы получите следующий результат:

INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added table 'products'
  Generating
  flask_app/migrations/versions/b9198aca3963_initial_migration.py
  ...done

Поскольку наша база данных еще не создана, этот вывод сообщает вам, что была обнаружена новая таблица с именем products и скрипт миграции с именем b9198aca3963 Initial_migration.py был создан внутри каталога с именем versions, где хранятся все различные версии миграции.

Часть b9198aca3963 в имени файла сценария миграции представляет собой случайный идентификатор, сгенерированный для идентификации различных миграций, чтобы они были разными для вас.

Чтобы понять, как работает сценарий миграции, откройте свой с помощью следующей команды. Убедитесь, что вы заменили b9198aca3963 идентификатором, который был сгенерирован для вас, и что вы находитесь в корневом каталоге flask_app:

nano migrations/versions/b9198aca3963_initial_migration.py

Помимо внутреннего импорта и настройки, этот сценарий первоначальной миграции будет иметь две основные функции, аналогичные следующим:

def upgrade():
    # ### commands auto-generated by Alembic - please adjust! ###
    op.create_table('products',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('name', sa.String(length=50), nullable=True),
    sa.PrimaryKeyConstraint('id')
    )
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto-generated by Alembic - please adjust! ###
    op.drop_table('products')
    # ### end Alembic commands ###
  • Функция upgrade() изменяет базу данных на основе изменений, обнаруженных командой flask dbmigrate. В этом случае была обнаружена новая таблица с именем products, поэтому функция upgrade() создает новую таблицу со столбцами, указанными в Product() модель базы данных, которую вы объявили в файле app.py.

  • Функция downgrade() удаляет изменения и восстанавливает состояние базы данных, которое было до обновления. В этом примере предыдущее состояние восстанавливается путем удаления таблицы products, которая будет создана функцией upgrade().

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

Теперь, когда сценарий миграции готов, вы можете использовать его для выполнения первоначального обновления. При этом будет создан файл базы данных app.db и таблица products. Для этого выполните следующую команду в каталоге flask_app:

flask db upgrade

Вывод будет похож на следующий:

INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> b9198aca3963, initial migration

Это сообщит вам, что обновление было успешно выполнено.

Новый файл базы данных app.db будет добавлен в вашу папку instance внутри вашего каталога flask_app.

Примечание. Первая миграция эквивалентна использованию db.create_all() в оболочке Flask.

Если вы внедрите Flask-Migrate в существующий проект с существующей базой данных, то обновление базы данных Flask завершится неудачей, поскольку файл базы данных уже существует. В этом случае используйте flask db Stamp, чтобы пометить базу данных как обновленную, вместо flask db update.

Создав базу данных и таблицу products, вы можете добавить в свою базу данных несколько продуктов. Вы сделаете это дальше.

Заполнение базы данных

Теперь вы будете использовать оболочку Flask, чтобы вставить несколько элементов в таблицу products.

Активировав виртуальную среду, выполните следующую команду для доступа к оболочке Flask:

flask shell

Внутри интерактивной оболочки запустите следующий код:

from app import db, Product

apple = Product(name="Apple")
orange = Product(name="Orange")
banana = Product(name="Banana")
db.session.add_all([apple, orange, banana])
db.session.commit()

Этот код делает следующее:

  • Импортирует объект db и модель Product из файла app.py.
  • Создает три экземпляра класса Product(), передавая имя для каждого продукта.
  • Добавляет новые продукты в сеанс базы данных с помощью метода db.session.add_all().
  • Применяет изменения к базе данных с помощью метода db.session.commit().

Дополнительные сведения о том, как использовать Flask-SQLAlchemy, см. в разделе «Как использовать Flask-SQLAlchemy для взаимодействия с базами данных в приложении Flask».

Выйдите из оболочки Flask:

exit()

Чтобы убедиться, что товары добавлены в базу данных, перезапустите оболочку Flask со свежей памятью:

flask shell

Затем выполните следующий код, чтобы просмотреть элементы в таблице продуктов:

from app import db, Product

for p in Product.query.all():
    print(p.name, p.id)

Здесь вы импортируете объект db и модель Product; затем вы используете цикл for для результата метода query.all(), чтобы получить доступ к каждому элементу в таблице продуктов и распечатать имя и идентификатор каждого элемента.

Результат будет следующим:

Apple 1
Orange 2
Banana 3

Вы успешно перенесли свою базу данных и заполнили таблицу продуктов тремя элементами. Мы изменим схему базы данных и добавим новый столбец price в таблицу products, а затем перенесем и обновим нашу базу данных, сохранив эти данные с помощью Flask-Migrate.

Шаг 04. Изменение модели базы данных

Теперь в вашей базе данных есть таблица продуктов, в которой хранится несколько элементов. На этом этапе вы будете использовать Flask-Migrate, чтобы добавить столбец price в таблицу products. Предположим, вы хотите сделать это без менеджера миграции базы данных. В этом случае вам необходимо сначала удалить всю таблицу products и создать ее заново с новым столбцом, в результате чего вы потеряете все существующие элементы продуктов. Однако с помощью Flask-Migrate вы можете добавить новый столбец, сохранив при этом существующие данные.

Добавление нового столбца цен

Чтобы добавить столбец цен в таблицу продуктов, откройте файл app.py и измените модель базы данных Product, которая определяет схему таблицы.

Внутри каталога flask_app откройте app.py для внесения изменений:

nano app.py

Отредактируйте класс Product(), добавив новый целочисленный столбец с именем price:

class Product(db.Model):
    __tablename__ = 'products'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    price = db.Column(db.Integer)

    def __repr__(self):
        return f'<Product {self.name}>'

Сохраните и закройте файл.

Модификация схемы базы данных завершена. Вы создадите новый сценарий миграции, чтобы применить его к базе данных и предотвратить потерю данных.

Создать миграцию

После изменения модели базы данных запустите команду flask dbmigrate для Flask-Migrate, чтобы обнаружить ваши изменения и создать новый сценарий миграции. Обязательно добавьте сообщение с описанием того, что вы изменили:

flask db migrate -m "add price column"

Как и при первоначальной миграции, вы получите такой результат:

INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added column 'products.price'
  Generating
  flask_app/migrations/versions/7ad34929a0f2_add_price_column.py
  ...  done

Это сообщит вам, что был обнаружен новый столбец и создан сценарий миграции.

Не забудьте просмотреть созданный сценарий миграции. В этом случае основные функции upgrade() и downgrade() будут такими:

def upgrade():
    # ### commands auto-generated by Alembic - please adjust! ###
    with op.batch_alter_table('products', schema=None) as batch_op:
        batch_op.add_column(sa.Column('price', sa.Integer(), nullable=True))
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto-generated by Alembic - please adjust! ###
    with op.batch_alter_table('products', schema=None) as batch_op:
        batch_op.drop_column('price')
    # ### end Alembic commands ###

Здесь функция upgrade() изменяет таблицу products и добавляет столбец price. Функция downgrade() удаляет столбец price(), восстанавливая предыдущую версию вашей базы данных.

Обновление базы данных

После изменения модели базы данных создайте сценарий миграции на основе этой модификации. Теперь вы можете применить изменения к базе данных с помощью команды upgrade, которая запускает функцию upgrade() в последнем сценарии миграции.

flask db upgrade

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

Чтобы проверить, что столбец price добавлен, запустите оболочку Flask:

flask shell

Затем просмотрите элементы продукта в базе данных и распечатайте значения столбцов:

from app import db, Product

for p in Product.query.all():
    print(p.name, p.id, p.price)

Вывод должен быть следующим:

Apple 1 None
Orange 2 None
Banana 3 None

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

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

Выйдите из оболочки Flask:

exit()

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

Шаг 05 — Понижение версии базы данных

На предыдущем шаге вы обновили исходную версию базы данных и добавили столбец price в ее таблицу products. Чтобы продемонстрировать, как восстановить предыдущее состояние при управлении миграцией базы данных, вы понизите текущую базу данных и удалите столбец price из таблицы products.

Чтобы понизить версию вашей базы данных и восстановить ее предыдущую версию, выполните следующую команду в каталоге flask_app:

flask db downgrade

Вывод сообщит вам, что версия базы данных изменилась и предыдущая версия восстановлена.

Чтобы проверить, удален ли столбец price, откройте оболочку Flask:

flask shell

Затем запустите запрос к модели Product, чтобы получить все элементы таблицы продуктов:

from app import db, Product
Product.query.all()

Вы должны получить сообщение об ошибке, указывающее, что в таблице products нет столбца price:

sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such column: products.price
[SQL: SELECT products.id AS products_id, products.name AS products_name, products.price AS products_price
FROM products]
(Background on this error at: https://sqlalche.me/e/20/e3q8)

Это подтверждает, что столбец price был успешно удален и что переход к более ранней версии базы данных прошел успешно, а ошибка возникает, поскольку у вас все еще есть столбец price, определенный в Product( ) внутри файла app.py.

Чтобы исправить эту ошибку, выйдите из оболочки Flask:

exit()

Затем откройте app.py в каталоге flask_app:

nano app.py

Измените модель Product(), удалив объявление столбца price, чтобы окончательная версия выглядела следующим образом:

class Product(db.Model):
    __tablename__ = 'products'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))

    def __repr__(self):
        return f'<Product {self.name}>'

Сохраните и закройте файл.

Чтобы проверить, исправлена ли ошибка, откройте оболочку Flask:

flask shell

Затем запросите все продукты:

from app import db, Product

Product.query.all()

Вывод должен быть следующим:

[<Product Apple>, <Product Orange>, <Product Banana>]

Это означает, что ошибка исправлена.

Наконец, вы можете удалить файл миграции, в имени которого содержится add_price_column, если он вам больше не нужен:

rm migrations/versions/7ad34929a0f2_add_price_column.py

Таким образом, вы успешно понизили версию своей базы данных и восстановили ее предыдущую версию.

Заключение

Вы создали небольшое приложение Flask с базой данных и интегрировали его с Flask-Migrate. Вы научились изменять модели баз данных, обновлять их до новой версии и откатывать до предыдущей версии.

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

  1. Измените модели базы данных.

  2. Создайте сценарий миграции с помощью команды flask dbmigrate.

  3. Просмотрите созданный сценарий миграции и при необходимости исправьте его.

  4. Примените изменения к базе данных с помощью команды flask db update.

  5. Чтобы восстановить предыдущую версию базы данных, используйте команду flask db downgrade.

Дополнительную информацию см. в документации Flask-Migrate.

Если вы хотите узнать больше о Flask, ознакомьтесь с другими руководствами из серии «Как создавать веб-приложения с помощью Flask».

Статьи по данной тематике: