首页 > 解决方案 > flask db init 返回“sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table”

问题描述

我一直在使用 sqlite 数据库在烧瓶中开发一个 Web 应用程序。到目前为止一切顺利,我知道一旦数据库存在,sqlite 在对表的更改方面受到限制。

但是,到目前为止,我已经能够毫无问题地修改 models.py 中几个模型的表(添加列、重命名列等)。注意到这里我确实使用

migrate = Migrate(app, db, render_as_batch=True)

在应用程序初始化中,已经需要实现对数据库的一些更改。

flask db migrate但是,现在,在向模型“用户”添加新列后尝试运行时,我收到了以下错误:

    Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/engine/base.py", line 1249, in _execute_context
    cursor, statement, parameters, context
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/engine/default.py", line 580, in do_execute
    cursor.execute(statement, parameters)
sqlite3.OperationalError: no such table: user

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/bin/flask", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.6/dist-packages/flask/cli.py", line 966, in main
    cli.main(prog_name="python -m flask" if as_module else None)
  File "/usr/local/lib/python3.6/dist-packages/flask/cli.py", line 586, in main
    return super(FlaskGroup, self).main(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/click/decorators.py", line 21, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/flask/cli.py", line 425, in decorator
    with __ctx.ensure_object(ScriptInfo).load_app().app_context():
  File "/usr/local/lib/python3.6/dist-packages/flask/cli.py", line 388, in load_app
    app = locate_app(self, import_name, name)
  File "/usr/local/lib/python3.6/dist-packages/flask/cli.py", line 240, in locate_app
    __import__(module_name)
  File "/home/arthur/Development/ISLWeb/islweb.py", line 1, in <module>
    from app import app, db
  File "/home/arthur/Development/ISLWeb/app/__init__.py", line 24, in <module>
    from app import routes, models
  File "/home/arthur/Development/ISLWeb/app/routes.py", line 11, in <module>
    from app.forms import (LoginForm, RegistrationForm, CreateLaunchForm, 
  File "/home/arthur/Development/ISLWeb/app/forms.py", line 93, in <module>
    class NewActionForm(FlaskForm):
  File "/home/arthur/Development/ISLWeb/app/forms.py", line 95, in NewActionForm
    users = User.query.all()
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/orm/query.py", line 3186, in all
    return list(self)
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/orm/query.py", line 3342, in __iter__
    return self._execute_and_instances(context)
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/orm/query.py", line 3367, in _execute_and_instances
    result = conn.execute(querycontext.statement, self._params)
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/engine/base.py", line 988, in execute
    return meth(self, multiparams, params)
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/sql/elements.py", line 287, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/engine/base.py", line 1107, in _execute_clauseelement
    distilled_params,
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/engine/base.py", line 1253, in _execute_context
    e, statement, parameters, cursor, context
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/engine/base.py", line 1473, in _handle_dbapi_exception
    util.raise_from_cause(sqlalchemy_exception, exc_info)
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/util/compat.py", line 398, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb, cause=cause)
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/util/compat.py", line 152, in reraise
    raise value.with_traceback(tb)
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/engine/base.py", line 1249, in _execute_context
    cursor, statement, parameters, context
  File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/engine/default.py", line 580, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: user
[SQL: SELECT user.id AS user_id, user.username AS user_username, user.email AS user_email, user.password_hash AS user_password_hash, user.has_admin_rights AS user_has_admin_rights, user.is_customer AS user_is_customer 
FROM user]
(Background on this error at: http://sqlalche.me/e/e3q8)

这对我来说很奇怪,因为:

  1. 表用户在(并且已经)在那里
  2. 我之前已经能够向用户模型添加列
  3. 我仍然可以将列添加到其他模型而不会出现错误

现在,我在这里和其他地方的许多问题中都看到了这个 sqlite3.OperationalError ,但它们似乎都与这里的情况无关,因为代码库之前运行良好,迁移也是如此(它们仍然与所有其他模型也是如此)另外,我尝试作为一种测试方式删除迁移文件夹以及数据库文件,重新开始:

flask db init

在我的理解中,它重新启动了整个数据库(包括新的迁移脚本)。有趣的是,这会引发与上述完全相同的错误。我也完全不明白,因为没有数据库可供读取。

我的用户模型如下(我试图添加评论的列):

class User(UserMixin, db.Model):
    
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), index=True, unique=True)
    email = db.Column(db.String(120), index=True, unique=True)
    password_hash = db.Column(db.String(128))
    actions = db.relationship('Action', backref='owner', lazy='dynamic')
    events = db.relationship('WebLogEvent', backref='user', lazy='dynamic')
    has_admin_rights = db.Column(db.Boolean)
    is_customer = db.Column(db.Boolean)
    #permissions = db.Column(db.String(256), index=True)
    
    def __repr__(self):
        return '<User {}>'.format(self.username)
        
    @staticmethod
    def table_header():
        return ["ID", "Username", "e-mail", "Admin"]
    
    def set_password(self, password):
        self.password_hash = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

    def as_table_row(self):
        return [self.id, self.username, self.email, self.has_admin_rights]

任何关于这里可能出现的问题的想法都非常受欢迎。

标签: pythonsqliteflaskflask-migrate

解决方案


您正在应用程序的全局范围内发出查询,在 class 中NewActionFormUser.query.all()根据您的堆栈跟踪,查询是。

问题在于全局范围内的代码在导入时执行。在很多情况下这没问题,但是数据库访问通常是有问题的,因为您必须在访问数据库之前创建和配置您的 Flask 应用程序实例。

所以解决办法是不在全局范围内查询数据库。您可能可以将该逻辑移动到表单的构造方法中。


推荐阅读