新版Flask-SQLAlchemy和Flask-Migrate的踩坑指南(2022.07)
一、版本环境
看了很多文章,没有写清楚环境的版本,导致解决方案根本对不上号,所以我先把本人使用的主要模块版本列出来
Flask==2.1.3
Flask-Migrate==3.1.0
Flask-Script==2.0.6
Flask-SQLAlchemy==2.5.1
本人开发环境为Windows + VSCode
二、遇到的问题
一开始,我按照网上的大部分教程所说,使用flask_script来执行数据迁移命令,主要代码如下:
from flask_migrate import Migrate,MigrateCommand
from flask_script import Manager
manager = Manager(app)
# flask-script集成的数据库操作
manager.add_command('db', MigrateCommand)
结果遇到一些错误,下面一一说明。
1.No module named 'flask._compat'
完整提示:
F:\Python\flask\flask_orm_admin>python3 main.py db init
Traceback (most recent call last):
File "main.py", line 6, in <module>
from flask_script import Manager
File "D:\Python3\lib\site-packages\flask_script\__init__.py", line 15, in <module>
from flask._compat import text_type
ModuleNotFoundError: No module named 'flask._compat'
然后搜解决办法,发现很多人给的解决办法就是降低Flask的版本,改用1.x的版本
我了个去,这叫什么解决方案?以后还都不用新版本了?后来找到一个靠谱的解决办法:
修改flask_script 文件就可以
It happened because the python searched on Flask._compat directory and It isn't there, so I changed like on below : (on flask_script/__init__.py)
Where:
from ._compat import text_type on original flask-script file
to :
from flask_script._compat import text_type
试了一下,果然不再报这个错了,踩过了第一个坑。
然后继续按网上教程操作,又遇到一个坑。。
2.cannot import name 'MigrateCommand' from 'flask_migrate'
完整提示“:
F:\Python\flask\flask_orm_admin>python3 main.py db init
Traceback (most recent call last):
File "main.py", line 5, in <module>
from flask_migrate import Migrate,MigrateCommand
ImportError: cannot import name 'MigrateCommand' from 'flask_migrate' (D:\Python3\lib\site-packages\flask_migrate\__init__.py)
其实我还没运行的时候,我的VSCode已经提示我找不到MigrateCommand了
解决办法:
网上一搜,给出的解决方案又是降级!真是服了!继续找,终于找到一篇有用的 https://www.jianshu.com/p/11ce08e078aa
发现flask_migrate已经不再支持flask_script了,所以没有了MigrateCommand
因此,在我的代码中去掉了flask_script相关的内容,对代码进行了调整。
三、数据迁移
准备就绪之后,开始数据迁移工作
由于不再使用flask_script,而是使用flask db命令,所以跟网上的教程有一些变化
执行flask db init,会报错:
F:\Python\flask\flask_orm_admin\server>flask db init
Usage: flask db init [OPTIONS]
Try 'flask db init --help' for help.
Error: Could not locate a Flask application. You did not provide the "FLASK_APP" environment variable, and a "wsgi.py" or "app.py" module wa
s not found in the current directory.
就是说,flask需要找到一个Flask的实例app,FLASK_APP通常指定为主程序
set FLASK_APP=main.py
然后再执行flask db init
此时可能会出现导入模块错误,比如找不到连接数据库的ext.py,考虑到应该是因为直接执行flask命令时可能找不到本项目的路径,需要在main.py头部加上一些代码:
import sys,os
curdir = os.path.dirname(__file__)
sys.path.append(curdir)
sys.path.append(curdir + "..\\")
这样就可以解决找不到模块的问题了,继续执行
F:\Python\flask\flask_orm_admin\server>flask db init
Creating directory F:\Python\flask\flask_orm_admin\server\migrations\versions ... done
Generating F:\Python\flask\flask_orm_admin\server\migrations\alembic.ini ... done
Generating F:\Python\flask\flask_orm_admin\server\migrations\env.py ... done
Generating F:\Python\flask\flask_orm_admin\server\migrations\README ... done
Generating F:\Python\flask\flask_orm_admin\server\migrations\script.py.mako ... done
Please edit configuration/connection/logging settings in 'F:\\Python\\flask\\flask_orm_admin\\server\\migrations\\alembic.ini' before proceeding.
这个提示信息看起来是正常的,继续执行flask db migrate,-m参数可以为本次迁移添加一个消息,就像git的提交消息一样,后续一旦有问题还可以回滚
F:\Python\flask\flask_orm_admin\server>flask db migrate -m "add t_user"
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 't_user'
Generating F:\Python\flask\flask_orm_admin\server\migrations\versions\5c8e40bf5e34_add_t_user.py ... done
提示信息正常,检测到新表t_user,并生成了一个5c8e40bf5e34_add_t_user文件,有兴趣的读者可以根据路径找到这个文件,看看里面的内容
接下来执行flask db upgrade
F:\Python\flask\flask_orm_admin\server>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 -> 5c8e40bf5e34, add t_user
没有报错,应该是正常的。此时可以打开数据库检查一下,会发现t_user表已经建立好了
接下来再添加一个t_admin表,建立相应的Model,在main.py中添加导入,然后重复migrate和upgrade的过程
F:\Python\flask\flask_orm_admin\server>flask db migrate -m "add t_admin"
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 't_admin'
Generating F:\Python\flask\flask_orm_admin\server\migrations\versions\d91575857413_add_t_admin.py ... done
F:\Python\flask\flask_orm_admin\server>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 5c8e40bf5e34 -> d91575857413, add t_admin
检查了一下也是正常的。
其它的一些情况,我把注释都写在源码里了,自行查看即可
四、添加数据
使用著名的Faker库,来向user表添加一些数据。
import sys
sys.path.append("..")
from faker import Faker
from main import create_app
#导入模型
from user.models import User
fake = Faker(locale="zh-CN")
app = create_app()
db = app.config["db"]
#添加10个用户
def addFakeUser():
try:
with app.app_context():
for _ in range(10):
user = User(username=fake.name())
user.password = fake.random_number(7)
user.email = fake.email()
user.phone = fake.phone_number()
user.money = fake.random_int()
user.userip = fake.ipv4()
print(user.username,user.email)
#添加并提交
db.session.add(user)
db.session.commit()
except Exception as e:
print("数据库操作失败")
raise
else:
return True
addFakeUser()
然后访问接口http://127.0.0.1:5000/user/list,就可以看到数据了!
相关代码已放在 https://gitee.com/achillis/flask_demo ,欢迎访问