4

Я пытаюсь реализовать python-social-auth в Flask. Я вымыл тонны перегибов, пытаясь одновременно интерпретировать 4 урока и полную книгу с флягами, и чувствую, что я достиг своего тупика с помощью Flask-migrate.Как использовать flask-migrate с другими declarative_bases

В настоящее время я использую следующий код для создания таблиц, необходимых для работы python-social-auth в среде flask-sqlalchemy.

from social.apps.flask_app.default import models 
models.PSABase.metadata.create_all(db.engine) 

Теперь они, очевидно, используют некоторую форму своей собственной базы, не связанную с моим фактическим db-объектом. Это, в свою очередь, заставляет Flask-Migrate полностью пропустить эти таблицы и удалить их при миграции. Теперь, очевидно, я могу удалить эти db-капли из каждого удаления, но я могу представить, что это одна из тех вещей, о которых в какой-то момент забудут, и внезапно у меня больше нет связей OAuth.

Я получил это решение для работы с использованием (и модификации) в manage.py командно-SyncDB как предложено the python-social-auth Flask example

Мигель Гринберг, автор Колба-Migrate отвечает here к проблеме, похоже, очень похож на мою.

Самый близкий, который я мог найти при переполнении стека, был this, но он не пролил слишком много света на всю вещь для меня, и ответ так и не был принят (и я не могу заставить его работать, у меня есть попробовал несколько раз)

для справки, вот мой manage.py:

#!/usr/bin/env python 

from flask.ext.script import Server, Manager, Shell 
from flask.ext.migrate import Migrate, MigrateCommand 


from app import app, db 

manager = Manager(app) 
manager.add_command('runserver', Server()) 
manager.add_command('shell', Shell(make_context=lambda: { 
    'app': app, 
    'db_session': db.session 
})) 

migrate = Migrate(app, db) 
manager.add_command('db', MigrateCommand) 

@manager.command 
def syncdb(): 
    from social.apps.flask_app.default import models 
    models.PSABase.metadata.create_all(db.engine) 
    db.create_all() 

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

и уточнить, дБ INIT/мигрирует/обновить команды только создать свой пользовательский стол (и миграции одно очевидно) , но не социальные, а команда syncdb работает для таблиц python-social-auth.

Я понимаю из ответа github, что это не поддерживается Flask-Migrate, но мне интересно, есть ли способ поиграть в таблицы PSABase, чтобы их подхватили db-объект, отправленный в Migrate ,

Любые предложения приветствуются.

(Кроме того, первый раз плакат. Я чувствую, что провел много исследований и попробовал немало решений, прежде чем я, наконец, пришел сюда, чтобы опубликовать сообщение. Если я пропустил что-то очевидное в руководящих принципах SO, Не стесняйтесь указать на это в личном сообщении, и я с радостью соглашусь)

ответ

2

Проблема в том, что у вас есть два набора моделей, каждый из которых имеет другой объект метаданных SQLAlchemy. Модели из PSA были созданы непосредственно из SQLAlchemy, в то время как ваши собственные модели были созданы через Flask-SQLAlchemy.

Колба-Migrate видит только модель, которые определены с помощью Колбы-SQLAlchemy, потому что db объект, который вы даете ему известен только о метаданных для этих моделей, он ничего не знает об этих других моделях PSA, которые обходили колбовую SQLAlchemy.

Итак, конечный результат заключается в том, что каждый раз, когда вы создаете миграцию, Flask-Migrate/Alembic находят эти таблицы PSA в db и решают удалить их, потому что они не видят никаких моделей для них.

Я думаю, что лучшим решением для вашей проблемы является настройка Alembic для игнорирования определенных таблиц. Для этого вы можете использовать конфигурацию include_object в модуле env.py, хранящемся в каталоге миграции.В основном вы собираетесь написать функцию, которую Alembic будет вызывать каждый раз, когда она наступает на новый объект при генерации сценария миграции. Функция вернет False, когда объект является одной из этих таблиц PSA, и True для всех остальных.

Обновление: Еще один вариант, который вы включили в ответ, который вы написали, состоит в объединении двух объектов метаданных в один, затем модели из вашего приложения и PSA проверяются вместе с Alembic.

У меня нет ничего против техники слияния нескольких объектов метаданных в одну, но я считаю, что приложение не должно отслеживать миграции в моделях, которые не являются вашими. Много раз Alembic не сможет точно отслеживать миграцию, поэтому вам может потребоваться внести небольшие изменения в сгенерированный скрипт, прежде чем применять его. Для моделей, которые являются вашими, вы можете обнаружить эти неточности, которые иногда появляются в сценариях миграции, но когда модели не являются вашими, я думаю, вы можете пропустить что-то, потому что вы не будете достаточно знакомы с изменениями, которые произошли в тех чтобы сделать хороший обзор сценария, созданного Alembic.

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

+0

Благодарим вас за ответ, Мигель. Хорошо, я почти полностью забыл об Alembic. Не могу ли я просто пропустить Flask-Migrate и использовать это напрямую? Мне кажется, что это может быть обмануто, если подумать, что это настройка с несколькими базами данных (в основном это с точки зрения Alembics). – Sjolus

+0

Хм, не уверен, что вы получите разные результаты с Alembic. Если вы настроите конфигурацию multidb (которую вы также можете настроить с помощью Flask-Migrate, btw), проблема будет отображаться с обеих сторон. Миграции для вашего обычного db будут по-прежнему пытаться удалить модели PSA, но в дополнение к этому миграция для стороны PSA также попытается удалить ваши таблицы. Один из способов избежать этого беспорядка - использовать две отдельные базы данных, тогда таблицы с одной стороны не будут видны другим. – Miguel

+0

А, да, они будут противоречить друг другу. Не было бы слишком плохо с отдельными db, но было бы легко пропустить для пользователей во время устранения неполадок, которые, как я думаю. Наверное, я мог бы просто реализовать социальный материал. Мне просто грустно было так близко к финишу. Это все работает, за исключением миграций, что необходимо, заставляя меня снова разорвать его и начать с нуля: P – Sjolus

3

После полезного ответа от Miguel here У меня есть новые ключевые слова для исследования. Я закончил с a helpful github-page, в котором были, кроме всего прочего, ссылки на Alembic bitbucket site, которые очень помогли.

В конце концов, я сделал это мой Alembic миграции env.py-файл:

from sqlalchemy import engine_from_config, pool, MetaData 

[...] 

# add your model's MetaData object here 
# for 'autogenerate' support 
# from myapp import mymodel 
# target_metadata = mymodel.Base.metadata 
from flask import current_app 
config.set_main_option('sqlalchemy.url', 
         current_app.config.get('SQLALCHEMY_DATABASE_URI')) 

def combine_metadata(*args): 
    m = MetaData() 
    for metadata in args: 
     for t in metadata.tables.values(): 
      t.tometadata(m) 
    return m 

from social.apps.flask_app.default import models 

target_metadata = combine_metadata(
    current_app.extensions['migrate'].db.metadata, 
    models.PSABase.metadata) 

Это, кажется, работает совершенно отлично.

+0

Я подтверждаю, что это должен быть принятый ответ в этом Q & A. Мне беспомощно нужно удалить инструкцию drop/create для всех социальных таблиц auth в файле миграции upgrade/downgrade. Имея вышеуказанное исправление, сначала будет обновляться и обновляться. Безупречное решение :) – swdev

0

Я использую две модели следующим образом: -

Один из них является использование с использованием БД в качестве

db = SQLAlchemy() 
app['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:' + POSTGRES_PASSWORD + '@localhost/Flask' 
db.init_app(app) 

class User(db.Model): 
    pass 

другой с базы, как

Base = declarative_base() 
uri = 'postgresql://postgres:' + POSTGRES_PASSWORD + '@localhost/Flask' 
engine = create_engine(uri) 
metadata = MetaData(engine) 
Session = sessionmaker(bind=engine) 
session = Session() 

class Address(Base): 
    pass 

Поскольку вы создали пользователя с db.Model вы можете использовать flask migrate для User и class Address used Base, которая обрабатывает извлечение ранее существовавшей таблицы из базы данных.

 Смежные вопросы

  • Нет связанных вопросов^_^