Flask-Migrate
In the actual development environment, database modification often occurs. Generally, we do not modify the database manually, but to modify the corresponding ORM model, and then map the model to the database. At this point, it would be very useful to have a tool dedicated to this kind of thing, and flask-migrate does it. Flask-migrate is an encapsulation based on Alembic and integrated into Flask. All migration operations are actually done by Alembic. It can track changes in the model and map changes to the database.
Flask-Migrate requires installation with the following commands:
pip install flask-migrate
To enable Flask-Migrate to manage the database in app, it is necessary to use Migrate(app,db) to bind app and database. Suppose there are the following app files:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from constants import DB_URI
from flask_migrate import Migrate
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
# Binding app and database
migrate = Migrate(app,db)
class User(db.Model):
id = db.Column(db.Integer,primary_key=True)
username = db.Column(db.String(20))
addresses = db.relationship('Address',backref='user')
class Address(db.Model):
id = db.Column(db.Integer,primary_key=True)
email_address = db.Column(db.String(50))
user_id = db.Column(db.Integer,db.ForeignKey('user.id'))
db.create_all()
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
After that, ORM can be mapped on the command line. To manipulate the current flask app, you first need to import the current app into the environment variable:
# windows
$env:FLASK_APP='your_app.py'
#linux/unix
export FLASK_APP='your_app.py'
After importing the current app into the environment variable, you need to initialize a migration folder:
flask db init
Then add the current model to the migration file:
flask db migrate
Finally, the corresponding database operations in the migration file are mapped to the database.
flask db upgrade
The above approach is to load the current app into the environment variable, which is a bit cumbersome, setting the environment variable every time. Another way is to call it directly through flask-script. Now refactor the previous project and set it to the following directory structure:
! [flaskmigrate project directory structure] (/assets/migrate.png)
The following explains the role of each document:
constants.py file: Constant file used to store database configuration.
# constants.py
HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'xt_flask_migrate'
USERNAME = 'root'
PASSWORD = 'root'
DB_URI = 'mysql+mysqldb://{}:{}@{}:{}/{}'.format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE)
ext.py file: Put db variables in a separate file, not in the main app file. The purpose of this is to create such a way as from your_app import db if db is referenced by multiple model files in large projects, but classes defined by model files are often introduced in your_app.py, which results in circular references. So the best way is to put it in a separate file that does not depend on other modules.
# ext.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
Model.py file: Model file, used to store all models, and note that because flask-script is used here to map models and tables, there is no need to create a database using db.create_all().
# models.py
from ext import db
class User(db.Model):
id = db.Column(db.Integer,primary_key=True)
username = db.Column(db.String(50))
addresses = db.relationship('Address',backref='user')
def __init__(self,username):
self.username = username
class Address(db.Model):
id = db.Column(db.Integer,primary_key=True)
email_address = db.Column(db.String(50))
user_id = db.Column(db.Integer,db.ForeignKey('user.id'))
def __init__(self,email_address):
self.email_address = email_address
Management.py file: This file is used to store the commands of mapping database. MigrateCommand is a command of flask-migrate integration. Therefore, to add to the script command, you need to use the way of manager.add_command('db',MigrateCommand). Later, you need to run the command of Python management.py DB xxx, which is actually to execute MigrateCommand.
# manage.py
from flask_migrate import Migrate,MigrateCommand
from ext import db
from flask_script import Manager
from flask import Flask
from constants import DB_URI
import models
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db.init_app(app)
migrate = Migrate(app,db)
manager = Manager(app)
manager.add_command('db',MigrateCommand)
if __name__ == '__main__':
manager.run()
flaskmigrate.py file: This is the main app file, run the file. And because DB is placed in another file, the database is bound using db.init_app(app).
# flaskmigrate.py
from flask import Flask
from ext import db
app = Flask(__name__)
db.init_app(app)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
Then run the command to initialize the migration file:
python manage.py db init
Then run the command to add the model mapping to the file:
python manage.py db migrate
Finally, add the mapping file to the database:
python manage.py db upgrade