关于alembic迁移修改models.py模型结构,却总是创建新的表的问题
之前尝试给公司做个小型的数据分析平台,使用vue+fastapi+sqlalchemy做前后端,使用request+lxml+apscheduler做爬虫框架。在搭建数据库的时候,发现修改模型(表结构),使用alembic生成迁移文件,修改数据表,生成的迁移文件总是会对老表重复create(add),然后在alembic upgrade head 的时候,就告诉你,什么表单已经存在,创建表单失败,明明你只是想修改表结构,然后他生成的迁移文件就创建个新表
如果出现了这种情况,主要原因有两种,也有可能两种问题同时都犯了
一般使用sqlalchemy构建ROM流程基本上都是这样:
# database.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = (
"mysql+mysqlconnector://用户名:密码@数据库地址:3306/数据库名"
)
engine = create_engine(SQLALCHEMY_DATABASE_URL, pool_size=1000, max_overflow=0)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
然后创建模型比如
# models.py
from sqlalchemy import Column, Integer, String, TIMESTAMP, Boolean, Float, TEXT
from sqlalchemy.dialects.mysql import LONGTEXT
from .database import Base
from sqlalchemy.sql import func
import arrow
class test1(Base):
__tablename__ = "tTest"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(200))
theType = Column(String(200))
注意这个表的名字,之后会是个
天坑
都创建完了,就该走alembic那一套流程了,随便百度一下都可以搜的到。
这时候如果你在写models.py的时候不注意下面这个命名的话:
__tablename__="tTest"
修改了模型结构,比如随便加一行:
# models.py
from sqlalchemy import Column, Integer, String, TIMESTAMP, Boolean, Float, TEXT
from sqlalchemy.dialects.mysql import LONGTEXT
from .database import Base
from sqlalchemy.sql import func
import arrow
class test1(Base):
__tablename__ = "tTest"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(200))
theType = Column(String(200))
test = Column(String(200))
再
alembic revision --autogenerate -m “test3”
生成迁移就会是这样:
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'tTest'
INFO [alembic.autogenerate.compare] Detected added index 'ix_tTest_id' on '['id']'
G:\xxxxxxxxx\API\alembic\versions\e82962d2959c_test3.py ... done
你会发现,你之前创建过的表tTest这里又创建了一遍,然后再迁移
alembic upgrade head
就开是疯狂报错了:
(python36) G:xxxxxxxxx\API>alembic upgrade head
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.runtime.migration] Running upgrade 158eae39a112 -> e82962d2959c, test3
.........
.........(中间还有好多省略了)
[SQL:
CREATE TABLE tTest(
id INTEGER NOT NULL AUTO_INCREMENT,
name VARCHAR(200),
theType VARCHAR(200),
test VARCHAR(200)
)
]
(Background on this error at: http://sqlalche.me/e/f405)
就是怎么都找不到毛病
原因是表的名字不能使用驼峰法来命名
因为不同的数据库,操作系统,不一定都兼容大写,比如数据库,使用驼峰法命名表名,会全部统一成小写
作者本人并不了解alembic具体内部是通过怎样的原理自动生成迁移文件的,个人看法是,生成迁移文件时会比对你models.py中的
__tablename__="tTest"
和数据库的表名做对比,如果表名字和数据库的一摸一样,就认为是修改操作,如果不一样就认为是新建设操作,然而,如果使用驼峰命名,它判断的时候是不一样的,就给你生成建表迁移文件,然后,迁移的时候,生成的sql语句的表名是一样的,所以执行迁移的时候就会报错,大概意思就是数据表已经存在,创建表语句执行失败,后面就是一大堆的error,结果就是迁移失败
你可以修改成这样:
__tablename__="t_test"
或者
__tablename__="ttest"
反正就是不要用驼峰法
这是第一个坑
第二个坑就是再配置alembic.ini这个文件的时候
这个不一定都适用,主要原因也没想明白,在配置alembic.ini,大部分人都会在配置这个配置项:
# version location specification; this defaults
# to alembic/versions. When using multiple version
# directories, initial revisions must be specified with --version-path
# version_locations = %(here)s/bar %(here)s/bat alembic/versions
# the output encoding used when revision files
# are written from script.py.mako
# output_encoding = utf-8
sqlalchemy.url = mysql+mysqlconnector://用户名:密码@数据库地址:3306/数据库名
会直接复制models.py中数据库的连接设置,这样有的时候也会导致上面说的那种问题,主要原因也没想明白,之后修改成这样:
# version location specification; this defaults
# to alembic/versions. When using multiple version
# directories, initial revisions must be specified with --version-path
# version_locations = %(here)s/bar %(here)s/bat alembic/versions
# the output encoding used when revision files
# are written from script.py.mako
# output_encoding = utf-8
# sqlalchemy.url = mysql+mysqlconnector://用户名:密码@数据库地址:3306/数据库名
sqlalchemy.url = mysql+pymysql://用户名:密码@数据库地址:3306/数据库名
问题就莫名其妙的消失了,具体原因也不明白。。。。。之后再想把,先把任务完成。。。。。。
那个,写文章只是为了记录之前的错误,让自己以后少犯错误,如果有什么不对的地方,请各位大佬指正,就不要喷脸骂人了,谢谢~
还有,本文章不拒绝转载但是要转载的话还请告知本人,谢谢大佬。。。。