环境背景
最近在写一个flask的web项目,数据库使用的是mysql8.0数据库,数据库的连接方式使用的是flask-sqlalchemy的映射方式。下面贴出自己的环境:
遇到的问题:
自己的一个用户表原来没有电话号码字段,现在要添加电话号码字段,由于不想删除原来已有的数据,所以使用flask-migrate
进行数据迁移,可以动态添加字段。
下面是启动app时会创建数据表,但是有一个问题就是以后如果要重新添加字段,就要把数据库删除,再重新创建,这样子的话数据库里的数据就没有了,再实际工作中肯定是不能这样子的。
# 文件名:app.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()# 学生表orm映射
class Student(db.Model):id = db.Column(db.Integer,primary_key=True,autoincrement=True)name = db.Column(db.String(32),nullable=False)def create_app():app = Flask(__name__)app.config.from_object('app.config') //导入数据库连接配置db.init_app(app)# 由于没有入栈,在这里手动推栈创建所有的表with app.app_context():db.create_all() //将所有的model创建到数据库中去,已有的就不能会更新了return appif __name__ == "__main__":app = create_app()app.run()
新建一个manager.py
文件用来添加数据表新增字段。
你要安装2个插件才可以添加新字段:
flask-script
flask-migrate
具体的使用和安装方法自己百度一下
# 文件名:manager.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommandapp = Flask(__name__)
app.config.from_object('config')db = SQLAlchemy(app)
migrate = Migrate(app, db)manager = Manager(app)
manager.add_command('db', MigrateCommand)class User(db.Model):id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(128))phone = db.Column(db.String(32))if __name__ == '__main__':manager.run()
接下来启动app.py
文件,该文件会在数据库创建一个表,只有两个字段:
现在在CMD中执行下面代码用来运行manager.py
文件:
1.python manager.py db init
初始化,生成migrations文件夹。
现在versions文件夹还是空的。
2.python manager.py db migrate
匹配你的Model和数据表字段是不是相等,并记录改动。
可以看到migrations文件下面多了一个.py
文件,这个是需要进行数据库操作的文件。下面来看一下里面的内容,这里是关键:这里是关键:这里是关键:
这里是关键:
"""empty messageRevision ID: 98f3357f2377 Revises: Create Date: 2020-04-28 22:59:32.709824"""
from alembic import op
import sqlalchemy as sa# revision identifiers, used by Alembic.
revision = '98f3357f2377'
down_revision = None
branch_labels = None
depends_on = Nonedef upgrade():# ### commands auto generated by Alembic - please adjust! ###op.create_table('student',sa.Column('id', sa.Integer(), nullable=False),sa.Column('name', sa.String(length=128), nullable=True),sa.Column('phone', sa.String(length=32), nullable=True),sa.PrimaryKeyConstraint('id'))# ### end Alembic commands ###def downgrade():# ### commands auto generated by Alembic - please adjust! ###op.drop_table('student')# ### end Alembic commands ###
可以看到在def upgrade
函数中的代码是要创建一个student
数据表
3.接下来执行更新操作:python manager.py db upgrade
报错:sqlalchemy.exc.ProgrammingError: (mysql.connector.errors.ProgrammingError) 1050 (42S01): Table 'student' already exists
这句话的意思就是说 :student
表已经有了,不能再创建了。这里的报错是sqlalchemy
的报错,因为flask-sqlalchemy
内部也是集成了sqlalchemy
的。
理清一下思路发现是在第二步执行:python manager.py db migrate
后生成的文件内容不正常导致的,不应该创建表,应该添加字段,网上搜寻了很久,没有能解决方案,一步一步的排查后发现是配置文件内部的问题。
DEBUG = True
SECRET_KEY = 'YIUGJGYUFUIGUJYGKUYF8970ASDODJQPIQP[AD/DA/D/QDQ/ERP]WRP'
DB_USERNAME = 'root'
DA_PASSWORD = '0728'
DB_HOST = '127.0.0.1'
DB_PORT = '3306'
DB_NAME = 'demo'
DB_URI = 'mysql+mysqlconnector://{}:{}@{}:{}/{}'.format(
DB_USERNAME,DA_PASSWORD,DB_HOST,DB_PORT,DB_NAME
)
# DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(
# DB_USERNAME,DA_PASSWORD,DB_HOST,DB_PORT,DB_NAME
# )
SQLALCHEMY_DATABASE_URI = DB_URI
自己使用了mysqlconnector
的连接方式来连接mysql数据库,更换成cymysql
后就好了。下面是更换后的配置文件:
DEBUG = True
SECRET_KEY = 'YIUGJGYUFUIGUJYGKUYF8970ASDODJQPIQP[AD/DA/D/QDQ/ERP]WRP'
DB_USERNAME = 'root'
DA_PASSWORD = '0728'
DB_HOST = '127.0.0.1'
DB_PORT = '3306'
DB_NAME = 'demo'
DB_URI = 'mysql+cymysql://{}:{}@{}:{}/{}'.format(
DB_USERNAME,DA_PASSWORD,DB_HOST,DB_PORT,DB_NAME
)
# DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(
# DB_USERNAME,DA_PASSWORD,DB_HOST,DB_PORT,DB_NAME
# )
SQLALCHEMY_DATABASE_URI = DB_URI
重新删除生产的文件夹后再次执行:
1.python manager.py db init
2.python manager.py db migrate
"""empty messageRevision ID: 093ca4538d74 Revises: Create Date: 2020-04-28 23:14:35.263170"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql# revision identifiers, used by Alembic.
revision = '093ca4538d74'
down_revision = None
branch_labels = None
depends_on = Nonedef upgrade():# ### commands auto generated by Alembic - please adjust! ###op.add_column('student', sa.Column('phone', sa.String(length=32), nullable=True))op.alter_column('student', 'name',existing_type=mysql.VARCHAR(collation='utf8mb4_general_ci', length=32),nullable=True)# ### end Alembic commands ###def downgrade():# ### commands auto generated by Alembic - please adjust! ###op.alter_column('student', 'name',existing_type=mysql.VARCHAR(collation='utf8mb4_general_ci', length=32),nullable=False)op.drop_column('student', 'phone')# ### end Alembic commands ###
现在def upgrade
里面的代码就是更新的代码了。
3.python manager.py db upgrade
后可以看到数据库里面的student
数据表就添加了新字段。
结束语:遇到问题不要慌,一步一步的来排查,发现问题的根源点,然后再分步测试就可以解决了.
后记:如果你的问题还没有解决,可以尝试把model里面的__tablename__= "student"
这样子的手动指定表名给删除试试。实在不行就不要映射迁移了,利用可视化数据化管理的软件可以直接操作数据库来添加字段也是可以的。