【问题标题】:sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such tablesqlalchemy.exc.OperationalError: (sqlite3.OperationalError) 没有这样的表
【发布时间】:2017-12-10 00:56:09
【问题描述】:

我对烧瓶很陌生,正在尝试自己建立一个博客,但遇到了 SQLite 操作错误的问题。我曾在 Github 和 Stackoverflow 上研究过类似的问题,但旧问题中的典型拼写错误或错误都没有发生在我身上。如果有人能帮助我,我将不胜感激,真的很棒,因为这个问题就像杀了我,已经花了我两天的时间,我感觉很糟糕。

在代码中,我定义了表名“users_table”并在开始时运行“db.create_all()”来创建表,但每次出现“no such table user_table”时都会出现错误提交更新用户信息。

这是我测试 SQLite 操作的方式:

(under /project) python3 manage.py shell
>>> u = User(email='foo@bar.com', username='foobar', password='player')
>>> db.create_all()
>>> db.session.add(u)
>>> db.session.commit()  # with following error message
Traceback (most recent call last):
  File "C:\...\Python\Python36-32\lib\site-packages\sqlalchemy\engine\base.py", line 1182, in _execute_context
  context)
  File "C:\...\Python\Python36-32\lib\site-packages\sqlalchemy\engine\default.py", line 470, in do_execute
  cursor.execute(statement, parameters)
sqlite3.OperationalError: no such table: users_table
...
...
  sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: users_table

我已将代码最小化为以下四个部分,可能会再次出现错误消息:

/project/app/__init__.py:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import config

db = SQLAlchemy()

def create_app(config_name):
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    config[config_name].init_app(app)
    db.init_app(app)
    return app

/project/app/models.py:

import os
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash
from flask import Flask

basedir = os.path.abspath(os.path.dirname(__file__))

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
db = SQLAlchemy(app)


class User(db.Model):
    __tablename__ = 'users_table'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(64), unique=True, index=True)
    username = db.Column(db.String(64), unique=True, index=True)
    password_hash = db.Column(db.String(128))

    def __repr__(self):
        return '<User %r>' % self.username

    @property
    def password(self):
        raise AttributeError('Password is not a readable attribute')

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

项目/config.py:

import os
basedir = os.path.abspath(os.path.dirname(\__file__))

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'fhuaioe7832of67^&*T#oy93'
    SQLALCHEMY_COMMIT_ON_TEARDOWN = True

    @staticmethod
    def init_app(app):
        pass

class DevelopmentConfig(Config):
    DEBUG = True
    SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')

config = {
    'development': DevelopmentConfig,
    'default': DevelopmentConfig,
}

项目/manage.py:

import os
from app import create_app, db
from app.models import User
from flask_script import Manager, Shell

app = create_app(os.getenv('FLASK_CONFIG') or 'default')
manager = Manager(app)

def make_shell_context():
    return dict(app=app, db=db, User=User)

manager.add_command("shell", Shell(make_context=make_shell_context))


if __name__ == '__main__':
    manager.run()

【问题讨论】:

  • 您要么需要创建迁移 Alembic(通过 Flask-Migrate),要么自己创建表。

标签: python-3.x sqlite flask sqlalchemy flask-sqlalchemy


【解决方案1】:

非常简单的解决方案:在 app.py 或 main.py 中,您只需添加以下代码行即可解决此问题:

@app.before_first_request
def create_tables():
    db.create_all()

【讨论】:

    【解决方案2】:

    在您的情况下,需要将以下代码添加到 __init__.py 中:

    from models import User, Role
    
    @app.shell_context_processor
    def make_shell_context():
        return dict(db=db, User=User, Role=Role)
    

    然后你做你以前的工作,都是工作。

    【讨论】:

      【解决方案3】:

      我刚刚完成了一个 Flask 应用程序的设置,并处理了这种问题。

      我强烈怀疑这里的问题是您在__init__.py 中创建的db 实例不知道models.py 的内容,包括User 类。 __init__.py 中的 db 对象与您在 models.py 中创建的 db 完全不同。因此,当您在__init__.py 中运行db.create_all() 时,它会检查它所知道的表列表并且没有找到任何表。我遇到了这个确切的问题。

      我发现模型(如 User)注册到模型类定义中列出的特定 db 对象(例如 class User(db.Model):)。

      所以基本上我的理解是,解决此问题的方法是使用用于定义模型的 db 的同一实例运行 db.create_all()。换句话说,从models.py 中运行db.create_all()

      这是我的代码,您可以看看我是如何设置的:

      app.py:

      #!flask/bin/python
      import os
      
      from flask import Flask
      
      
      class CustomFlask(Flask):
          jinja_options = Flask.jinja_options.copy()
          jinja_options.update(dict(
              variable_start_string='%%',  # Default is '{{', I'm changing this because Vue.js uses '{{' / '}}'
              variable_end_string='%%',
          ))
      app = CustomFlask(__name__)
      
      app.config['SECRET_KEY'] = 'hard to guess string'
      
      import yaml
      if os.environ['SERVER_ENVIRONMENT'] == 'PRODUCTION':
          config_filename = "production.yaml"
      elif os.environ['SERVER_ENVIRONMENT'] == 'LOCAL':
          config_filename = "local.yaml"
      else:
          config_filename = "local.yaml"
      
      base_directory = path = os.path.dirname(os.path.realpath(__file__))
      
      with open(base_directory + "/config/" + config_filename) as config_file:
          config = yaml.load(config_file)
      
      db_config = config['database']
      SQLALCHEMY_DATABASE_URI = "mysql+mysqlconnector://{username}:{password}@{hostname}/{databasename}".format(
          username=db_config['username'],
          password=db_config['password'],
          hostname=db_config['hostname'],
          databasename=db_config['databasename'],
      )
      app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI
      app.config["SQLALCHEMY_POOL_RECYCLE"] = 299
      
      from flask_sqlalchemy import SQLAlchemy
      db = SQLAlchemy(app)
      db.app = app
      
      
      def clear_the_template_cache():
          app.jinja_env.cache = {}
      
      app.before_request(clear_the_template_cache)
      
      from flask_login import LoginManager
      login_manager = LoginManager()
      login_manager.init_app(app)
      
      
      @login_manager.user_loader
      def load_user(email):
          from models import User
          return User.query.filter_by(email=email).first()
      
      
      if __name__ == '__main__':
          from routes import web_routes
          app.register_blueprint(web_routes)
      
          from api import api
          app.register_blueprint(api)
      
          # To get PyCharm's debugger to work, you need to have "debug=False, threaded=True"
          #app.run(debug=False, threaded=True)
          app.run(debug=True)
      

      models.py:

      from app import db
      
      import datetime
      from werkzeug.security import generate_password_hash, \
           check_password_hash
      
      
      class Song(db.Model):
          id = db.Column(db.Integer, primary_key=True, autoincrement=True)
          name = db.Column(db.String(80))
          datetime_created = db.Column(db.DateTime, default=datetime.datetime.utcnow())
          user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
          lines = db.relationship('Line', cascade="all,delete", backref=db.backref('song', lazy='joined'), lazy='dynamic')
          is_deleted = db.Column(db.Boolean, default=False)
      
      
      class Line(db.Model):
          id = db.Column(db.Integer, primary_key=True, autoincrement=True)
          user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
          song_id = db.Column(db.Integer, db.ForeignKey('song.id'))
          spans_of_time = db.relationship('SpanOfTime', cascade="all,delete", backref=db.backref('line', lazy='joined'), lazy='dynamic')
      
      
      class SpanOfTime(db.Model):
          id = db.Column(db.Integer, primary_key=True, autoincrement=True)
          user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
          line_id = db.Column(db.Integer, db.ForeignKey('line.id'))
          starting_64th = db.Column(db.Integer)  # I'm assuming the highest-granularity desired will be a 1/64th note-length.
          length = db.Column(db.Integer)  # I guess this'll be in 1/64th notes, so a 1/16th note will be '4'.
          content = db.Column(db.String(80))
      
      
      class User(db.Model):
          id = db.Column(db.Integer, primary_key=True, autoincrement=True)
          email = db.Column(db.String(80), primary_key=True, unique=True)
          display_name = db.Column(db.String(80), default="A Rhymecraft User")
          password_hash = db.Column(db.String(200))
          datetime_subscription_valid_until = db.Column(db.DateTime, default=datetime.datetime.utcnow() - datetime.timedelta(days=1))
          datetime_joined = db.Column(db.DateTime, default=datetime.datetime.utcnow())
          songs = db.relationship('Song', cascade="all,delete", backref=db.backref('user', lazy='joined'), lazy='dynamic')
      
          def __init__(self, email, password):
              self.email = email
              self.set_password(password)
      
          def __repr__(self):
              return '<User %r>' % self.email
      
          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 is_authenticated(self):
              return True
      
          def is_active(self):
              return True
      
          def is_anonymous(self):
              return False
      
          def get_id(self):
              return str(self.email)
      
      
      def init_db():
          db.create_all()
      
          # Create a test user
          new_user = User('a@a.com', 'aaaaaaaa')
          new_user.display_name = 'Nathan'
          db.session.add(new_user)
          db.session.commit()
      
          new_user.datetime_subscription_valid_until = datetime.datetime(2019, 1, 1)
          db.session.commit()
      
      
      if __name__ == '__main__':
          init_db()
      

      【讨论】:

      • 你拯救了我的一天! init 中的数据库确实是隔离的,我只是将 init 中的数据库导入模型而不是创建一个新的,一切正常!谢谢!
      • 是否可以准确地显示你是如何做到的,或者models.py文件中的import语句?
      • @chibole 我不确定你指的是什么;上面的 models.py 示例是否包含导入语句:from app import db
      • @Nathan,我想确切地知道你为解决这个问题做了什么,你只是简单地解释了它。无论如何,我也通过运行迁移然后迁移升级得到了解决方案。它对我有用。
      • 我不敢相信这有多么简单!你真的救了我,我在过去的两周里一直在试图解决这个问题,我的网页刚刚加载而没有错误消息!!
      猜你喜欢
      • 2021-07-24
      • 2020-09-16
      • 2020-12-01
      • 2021-01-12
      • 2021-11-02
      • 2020-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多