2017-07-06 6 views
2

Je suis frais de flacon et essayait de construire un blog sur mon propre, et j'ai rencontré un problème avec l'erreur d'opération SQLite. J'ai étudié un problème similaire sur Github et Stackoverflow, mais aucune faute typique ou erreur dans les vieilles questions ne m'arrive. Ce serait apprécié et vraiment génial si quelqu'un peut m'aider parce que ce problème est comme me tuer et m'a déjà coûté deux jours, je me sens vraiment mal.sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) pas une telle table

Dans le code j'ai défini le nom de la table qui est "users_table" et exécutez "db.create_all()" au début pour créer la table, mais l'erreur persiste avec "no such table user_table" un commit arrive pour la mise à jour des informations de l'utilisateur.

Voici comment je teste le fonctionnement SQLite:

(under /project) python3 manage.py shell 
>>> u = User(email='[email protected]', 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 

Je minimisé le code en quatre sections suivantes, qui peut se reproduire le message d'erreur:

/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) 

projet/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, 
} 

projet/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() 
+0

Soit vous devez créer les migrations Alambic (via Flask- Migrer) ou créer la table vous-même. –

Répondre

2

Je viens de faire la mise en place d'une application et je Flask eu affaire à ce genre de problème.

Je soupçonne fortement est ici le problème que l'instance de db que vous créez dans __init__.py ne connaît pas le contenu de models.py, y compris la classe User. L'objet db dans __init__.py est un objet totalement séparé du db que vous créez dans models.py. Ainsi, lorsque vous exécutez db.create_all() dans __init__.py, il vérifie la liste des tables qu'il connaît et n'en trouve aucune. Je suis tombé sur ce problème précis. Ce que j'ai découvert est que les modèles (comme User) sont enregistrés avec l'objet db particulier qui est répertorié dans la définition de classe du modèle (par exemple class User(db.Model):). Donc, fondamentalement, je crois comprendre que la façon de résoudre ce problème est d'exécuter db.create_all() en utilisant la même instance de db qui est utilisée pour définir les modèles. En d'autres termes, exécutez db.create_all() à partir de models.py.

Voici mon code afin que vous puissiez voir comment je l'ai mis en place:

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('[email protected]', '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() 
+0

Vous avez sauvé ma journée!Il est vrai que le db dans __init__ est réellement isolé, et j'ai juste importé le db de __init__ dans des modèles au lieu d'en créer un nouveau et tout a juste fonctionné! Je vous remercie! – nonemaw