我正在尝试使用Flask-Migrate的基本Flask-Security应用程序。我有两个主要的py文件:app.py和db_migrate.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()
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()
我已经运行了迁移工具来初始化和迁移db一次,以创建一个新的数据库,并且它有效:
python db_manager.py db init
python db_manager.py db migrate
我试图运行app.py.它在localhost上正确提供,但是当我尝试登录用户时,我得到以下OperationalError:
OperationalError:(OperationalError)没有这样的表: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 user \ nWHERE lower(user.email)LIKE lower(?)\ n LIMIT? OFFSET?' (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')
答案 0 :(得分:3)
Flask-Migrate / Alembic的工作流程如下:
db init
您在创建迁移存储库时执行一次,而不是再次执行此操作。
db migrate
您运行此命令以生成迁移脚本。该命令的输出告诉您创建迁移脚本的位置,并显示放入其中的内容的摘要。您的数据库在此阶段尚未修改。
查看迁移脚本
这非常重要。自动迁移并不完美,您必须查看生成的脚本并进行必要的更正。
db upgrade
这会将迁移应用到您的数据库,从而有效地进行必要的架构更改。
您现在可以使用您的数据库了。当您对模型进行更多更改时,请返回步骤2并重复循环。
根据您的说明,您可能错过了第4步upgrade
来电。
作为旁注,你的两个脚本之间有一些重复,你应该尝试合并它们。看看人们如何构建分散在多个模块或包中的Flask应用程序。