использование Flask-Migrate вместе с Flask-Security

Я пытаюсь заставить базовое приложение Flask-Security работать с Flask-Migrate. У меня есть два основных файла py: app.py и db_migrate.py.

app.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'] = '[email protected]'
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. Он правильно работает на локальном хосте, но затем, когда я пытаюсь войти в систему, я получаю следующую ошибку OperationalError:

OperationalError: (OperationalError) нет такой таблицы: пользователь u'SELECT user.id КАК user_id, user.email КАК user_email, user.password КАК user_password, user.active КАК user_active, user.confirmed_at КАК user_confirmed_at, user.favcolor КАК user_favcolor \nFROM пользователь \nГДЕ ниже(user.email) НРАВИТСЯ ниже(?)\n ПРЕДЕЛ ? КОМПЕНСИРОВАТЬ ?' (u'[email protected]', 1, 0)

По сути, я сомневаюсь, что правильно создаю user_datastore и security, поскольку мне, вероятно, не следует импортировать User и Role таким образом, но я не уверен, как правильно получить к ним доступ.

РЕДАКТИРОВАТЬ:

Я добавил эту последнюю команду, благодаря предложению:

python db_manager.py db ugrade

Но теперь я получаю эту ошибку, когда пытаюсь подтвердить регистрацию пользователя по электронной почте:

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


person b_g    schedule 25.06.2014    source источник


Ответы (1)


Рабочий процесс с Flask-Migrate/Alembic выглядит следующим образом:

  1. db init

    Это вы делаете один раз при создании репозитория миграции и больше никогда.

  2. db migrate

    Вы запускаете это, чтобы создать сценарий миграции. Вывод команды сообщает вам, где был создан сценарий миграции, и показывает сводку того, что в него было помещено. Ваша база данных не была изменена на данном этапе.

  3. просмотрите скрипт миграции

    Это очень важно. Автоматическая миграция не идеальна, вы должны просмотреть сгенерированный сценарий и внести необходимые исправления.

  4. db upgrade

    Это применяет миграцию к вашей базе данных, эффективно внося необходимые изменения в схему.

  5. Теперь вы можете использовать свою базу данных. Когда вы внесете дополнительные изменения в свои модели, вернитесь к шагу 2 и повторите цикл.

Судя по вашему описанию, вы, возможно, пропустили шаг 4, вызов upgrade.

В качестве примечания: у вас есть дублирование между вашими двумя сценариями, вы должны попытаться объединить их. Посмотрите, как люди создают приложения Flask, разделенные на несколько модулей или пакетов.

person Miguel    schedule 25.06.2014
comment
Спасибо! Я также последовал вашему совету, так как код создавал 2 соединения с базой данных. - person b_g; 30.06.2014