Использование sqlalchemy-континуума с flask-sqlalchemy и flask-migrate - PullRequest
0 голосов
/ 27 июня 2018

Я пытаюсь заставить sqlalchemy-континуум работать вместе с flask-sqlalchemy и flask-migrate. Мой __init__.py файл выглядит так:

import os

from flask import Flask

def create_app():
    """Create and configure an instance of the Flask application."""
    app = Flask(__name__, instance_relative_config=True)

    app.config.from_mapping(
        SQLALCHEMY_DATABASE_URI='postgres+psycopg2://{}:{}@{}:{}/{}'.format(
            os.environ['POSTGRES_USER'],
            os.environ['POSTGRES_PASSWORD'],
            os.environ['POSTGRES_HOST'],
            os.environ['POSTGRES_PORT'],
            os.environ['POSTGRES_DB']
        ),
        SQLALCHEMY_TRACK_MODIFICATIONS=False
    )

    try:
        os.makedirs(app.instance_path)
    except OSError:
        pass

    from .models import db, migrate
    db.init_app(app)
    migrate.init_app(app, db)

    return app

Мой файл models.py выглядит так:

import sqlalchemy
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from sqlalchemy_continuum import make_versioned


db = SQLAlchemy()
migrate = Migrate()

make_versioned(user_cls=None)

class User(db.Model):
    __versioned__ = {}
    __tablename__ = 'user'

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    password = db.Column(db.String(20), unique=True, nullable=False)

    def __repr__(self):
        return '<User {} - {}>'.format(self.username, self.email)

sqlalchemy.orm.configure_mappers()

Затем я запускаю следующие команды flask-migrate для инициализации и переноса базы данных:

flask db init
flask db migrate
flask db upgrade

Вывод команды обновления flask db, кажется, показывает правильные создаваемые таблицы:

INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added table 'transaction'
INFO  [alembic.autogenerate.compare] Detected added table 'user'
INFO  [alembic.autogenerate.compare] Detected added table 'user_version'
INFO  [alembic.autogenerate.compare] Detected added index 'ix_user_version_end_transaction_id' on '['end_transaction_id']'
INFO  [alembic.autogenerate.compare] Detected added index 'ix_user_version_operation_type' on '['operation_type']'
INFO  [alembic.autogenerate.compare] Detected added index 'ix_user_version_transaction_id' on '['transaction_id']'

В оболочке python я могу сделать следующее:

>>> from test_flask.__init__ import create_app
>>> from test_flask.models import db, User

>>> app = create_app()
>>> with app.app_context():
...     user = User(username='devuser', email='devuser@gmail.com', 
password='devpassword')
...     db.session.add(user)
...     db.session.commit()

Кажется, это работает нормально, но когда я пытаюсь получить доступ к элементу в атрибуте версии, используя:

>>> user.versions[0]

Я получаю следующую ошибку:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/orm/dynamic.py", line 254, in __getitem__
  attributes.PASSIVE_NO_INITIALIZE).indexed(index)
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/orm/dynamic.py", line 359, in indexed
  return list(self.added_items)[index]
IndexError: list index out of range

Команда:

>>> user.versions

возвращается:

<sqlalchemy.orm.dynamic.AppenderQuery object at 0x7f6515d3a898>

Это не похоже на ожидаемое поведение атрибута версии, как указано в документах sqlalchemy-континуум . Есть идеи, что я сделал не так?

1 Ответ

0 голосов
/ 04 июля 2018

Эта ошибка может произойти в двух случаях, как минимум:

  • Вы не сделали коммит после некоторого UPDATE или INSERT
  • или вы не в app контексте

В вашем примере из оболочки фляги все операторы должны находиться внутри блока контекста:

>>> with app.app_context():
...     user = User(username='devuser2', email='devuser2@gmail.com', password='devpassword2')
...     db.session.add(user)
...     db.session.commit()
...     user.versions[0].username
...     user.username='devuser_fixed'
...     db.session.commit()    
...     user.versions[1].username

#'devuser'
#'devuser_fixed'

Вне контекста, user все еще жив, переменная остается в памяти, но сеанс, связанный с базой данных, потерян.


Примечание: если 2-й коммит отсутствует, user.versions[1] будет доступен только в реальном сеансе контекста. Поэтому, если вы выйдете из этого контекста и отметите user.versions[1], вы столкнетесь с той же ошибкой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...