Как выполнить миграцию 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-ответ ("
, когда корневой URL-адрес доступен.Hello, World!
")
Выполните следующую команду, чтобы проверить правильность настройки приложения. Это запустит приложение 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:
Измените модели базы данных.
Создайте сценарий миграции с помощью команды
flask dbmigrate
.Просмотрите созданный сценарий миграции и при необходимости исправьте его.
Примените изменения к базе данных с помощью команды
flask db update
.Чтобы восстановить предыдущую версию базы данных, используйте команду
flask db downgrade
.
Дополнительную информацию см. в документации Flask-Migrate.
Если вы хотите узнать больше о Flask, ознакомьтесь с другими руководствами из серии «Как создавать веб-приложения с помощью Flask».