下面記錄一下SQLAlchemy使用的技巧。
在多模塊下定義models
- 如果由多個藍圖下讀定義了model模塊,在初始化的時候需要加載到上下文中。
當使用flask_Migrate遷移數據庫的時候,當執行:
python manage.py db migrate -m '修改說明'
db會默認去上下文中尋找定義的models模型,所以必須在初始化app的時候加載相關models的上下文;因此所有相關的model.py文件都應該在初始化app的時候:
from XXX import model
數據遷移的坑
- SQLAlchemy當model發生了修改的時候,其是不能識別字段的的類型和字段大小的。
from extensions import db
class User(db.model)
__tablename__ = 'users'
user_id = db.Column(db.String(8), primary_key=True)
# 改為
class User(db.model)
__tablename__ = 'users'
user_id = db.Column(db.String(20), primary_key=True)
問題:直接遷移會出現no change,因為不會檢測字段的類型。
辦法:修改字段的名字遷移后再將字段改回遷移,相當於刪除原來的字段重新創建;
- 當當前的versions和數據庫的版本不一致導致無法遷移時。
辦法:
# 刪除原來的migrations文件夾;
# 去數據庫刪除alembic_version表的內容;
# 重新執行數據庫遷移操作;
手動初始化SQLAlchemy
在有些時候,我們沒有初始化APP,但是又想使用models中定義的模型和數據庫的ORM操作,那么就需要手動初始化了。
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from models import AdminUser
# 創建一個配置對象
engine = create_engine('mysql+pymysql://username:passwd@ip:port/db?charset=utf8', convert_unicode=True)
# 創建一個會話
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
# 初始化查詢對象
AdminUser.query = db_session.query_property()
# 下面就跟在框架中一樣了
admin = AdminUser()
admin.id = 1
admin.username = username
admin.password = pwd
db_session.add(admin)
db_session.commit()
查詢報錯:sqlalchemy.exc.InvalidRequestError: Can't reconnect until invalid transaction is rolled back
-
原因是:連接斷開后,事務沒有回滾,殘留的鎖導致后續的查詢報錯.sqlalchemy對每一個查詢和插入等操作都是一個事務。
-
解決:在所有的數據庫操作的時候捕捉異常進行事務的回滾。
# main.py
from models import OrderInfo
from sqlalchemy.exc import InvalidRequestError
try:
order = OrderInfo.query.filter_by(task_id=user_dict.get('task_id')).first()
order.status = 'COMPLETE'
db.session.commit()
except InvalidRequestError:
db.session.rollback()
except Exception as e:
print(e)
