1

我正在尝试让一个基本的 Flask-Security 应用程序与 Flask-Migrate 一起使用。我有两个主要的 py 文件:app.py 和 db_migrate.py

应用程序.py:

from flask import Flask, render_template, request, session
from flask.ext.babel import Babel
from flask.ext.mail import Mail
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.security import Security, SQLAlchemyUserDatastore, UserMixin, RoleMixin    
import os
basedir = os.path.abspath(os.path.dirname(__file__)) #should be __ file __ with no spaces

# Create app
app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SECRET_KEY'] = 'super-secret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'app.db')
app.config['DEFAULT_MAIL_SENDER'] = 'info@site.com'
app.config['SECURITY_REGISTERABLE'] = True
app.config['SECURITY_CONFIRMABLE'] = True
app.config['SECURITY_RECOVERABLE'] = True
app.config.from_object('config.email')

# Setup mail extension
mail = Mail(app)

# Setup babel
babel = Babel(app)

@babel.localeselector
def get_locale():
    override = request.args.get('lang')

    if override:
        session['lang'] = override

    rv = session.get('lang', 'en')
    return rv

# Create database connection object
db = SQLAlchemy(app)

# Setup Flask-Security
from db_manager import User, Role #THIS IS PROBABLY WRONG!

user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)

#db.create_all()

# Views
@app.route('/')
def home():
    return render_template('index.html')

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

db_migrate.py:

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.script import Manager
from flask.ext.migrate import Migrate, MigrateCommand
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.security import Security, SQLAlchemyUserDatastore, UserMixin, RoleMixin

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

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

db = SQLAlchemy(app)
migrate = Migrate(app, db)

manager = Manager(app)
manager.add_command('db', MigrateCommand)

# Define models
roles_users = db.Table('roles_users',
        db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
        db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))

class Role(db.Model, RoleMixin):
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(80), unique=True)
    description = db.Column(db.String(255))

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(255), unique=True)
    password = db.Column(db.String(255))
    active = db.Column(db.Boolean())
    confirmed_at = db.Column(db.DateTime())
    favcolor = db.Column(db.String(255))
    roles = db.relationship('Role', secondary=roles_users,
                            backref=db.backref('users', lazy='dynamic'))

    def __str__(self):
        return '<User id=%s email=%s>' % (self.id, self.email)

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

我已经运行了迁移工具来初始化和迁移数据库一次,以创建一个新的数据库,它起作用了:

python db_manager.py db init
python db_manager.py db migrate

我试图运行 app.py。它在 localhost 上正常运行,但是当我尝试登录用户时,我收到以下 OperationalError:

OperationalError: (OperationalError) no such table: user u'SELECT user.id AS user_id, user.email AS user_email, user.password AS user_password, user.active AS user_active, user.confirmed_at AS user_confirmed_at, user.favcolor AS user_favcolor \nFROM用户\nWHERE lower(user.email) LIKE lower(?)\n LIMIT ? 抵消 ?' (u'xxx@xxx.com', 1, 0)

基本上,我怀疑我正在创建user_datastore并且security正确,因为我可能不应该以这种方式导入User-Role但我不确定如何正确访问它们。

编辑:

由于建议,我添加了这个最终命令:

python db_manager.py db ugrade

但是,现在当我尝试通过电子邮件确认用户注册时出现此错误:

(InvalidRequestError: Object '' is already attached to session '1' (this is '3')

4

1 回答 1

4

Flask-Migrate/Alembic 的工作流程如下:

  1. db init

    您在创建迁移存储库时执行一次,以后再也不会这样做。

  2. db migrate

    您运行它以生成迁移脚本。该命令的输出告诉您迁移脚本的创建位置,并显示其中的内容摘要。您的数据库在此阶段尚未修改。

  3. 查看迁移脚本

    这个非常重要。自动迁移并不完美,您必须查看生成的脚本并进行必要的更正。

  4. db upgrade

    这会将迁移应用到您的数据库,从而有效地进行必要的架构更改。

  5. 您现在可以使用您的数据库。当您对模型进行更多更改时,返回第 2 步并重复该循环。

根据您的描述,您可能错过了第 4 步,即upgrade通话。

作为旁注,您的两个脚本之间有一些重复,您应该尝试合并它们。看看人们如何构建跨多个模块或包的 Flask 应用程序。

于 2014-06-25T15:30:59.857 回答