使用Flask工厂模式集成Flask-SQLAlchemy无法创建SQLite数据库报错
问题根源
- 两个独立的SQLAlchemy实例:你在
models.py中初始化了一个全局db对象,又在create_db函数中重新创建了一个新的SQLAlchemy(app)实例,两个实例没有关联,模型绑定的是models里的db,你用新的db调用create_all自然找不到模型,也连不上正确的配置。 - 缺应用上下文:工厂模式下,
db.create_all()这类依赖应用上下文的操作,必须显式推送应用上下文才能执行,不能直接在工厂函数里裸调用。 - 实例目录未提前创建:SQLite不会自动生成父级目录,如果项目根目录下的
instance文件夹不存在,就会报无法创建/打开数据库的错误。 - 模型构造函数直接调用
current_app:FileModel的__init__方法直接访问current_app,模型类加载/实例化时如果没有活跃上下文会直接抛出异常。
修复方案
1. 统一全局SQLAlchemy实例,修改__init__.py代码
from flask import Flask from flask_sqlalchemy import SQLAlchemy import os # 提前导入models里的全局db,不要重复创建 from pdfextractor.models import db def create_db(app: Flask): app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///instance/pdfextractor.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # 直接用导入的db初始化app,不要重新new SQLAlchemy db.init_app(app) # 显式推送应用上下文后再执行create_all with app.app_context(): # 确保instance目录存在 os.makedirs(app.instance_path, exist_ok=True) db.create_all() db.session.commit() def create_app(test_config=None): # create and configure the app app = Flask(__name__, instance_relative_config=True) if test_config is None: # load the instance config, if it exists, when not testing app.config.from_pyfile('config.py', silent=True) else: # load the test config if passed in app.config.from_pyfile('config.py', silent=False) app.config.update(test_config) create_db(app) from pdfextractor import router app.register_blueprint(router.bp) return app
2. 修改models.py代码,调整构造函数的上下文调用逻辑
import pdftotext from datetime import datetime from pathlib import Path from flask import current_app from shutil import copyfile from flask_sqlalchemy import SQLAlchemy # 全局唯一的db实例 db = SQLAlchemy() class FileModel(db.Model): id = db.Column(db.Integer, primary_key=True) content = db.Column(db.String(), unique=True, nullable=False) datetime = db.Column(db.String(255), unique=True, nullable=False) def __init__(self: object, content=None, datetime=None): self.content = content self.datetime = datetime # 用到current_app的逻辑移到内部,确保调用时上下文已就绪 self._output_folder = Path(current_app.config['DATA_FOLDER']) if not self._output_folder.exists(): self._output_folder.mkdir(parents=True, exist_ok=True) def __repr__(self): return '<File %r>' % (self.content, self.datetime)
内容的提问来源于stack exchange,提问作者snooker9
相关产品推荐
相关产品推荐

