Использование декларативной sqlalchemy у внешнего работника

У меня есть веб-приложение, написанное на python с использованием Flask и sqlalchemy. Это приложение работает на Heroku, и как рабочий я использую расширение Ironworker, у меня все мои модели определены в модуле моделей следующим образом:

from app import db

class Player(db.Model):
    __tablename__ = 'players'
    id = db.Column(db.Integer, primary_key=True)
    ....
    type = db.Column(db.String(50))

    def __init__(self, ....):
        ....

    __mapper_args__ = {
        'polymorphic_identity':'player',
        'polymorphic_on':type
    }

class Outfielder(Player):
    __tablename__ = 'outfielders'
    id = db.Column(db.Integer, db.ForeignKey('players.id'), primary_key=True)

    __mapper_args__ = {
        'polymorphic_identity':'outfielder'
    }

class Goalkeeper(Player):
    __tablename__ = 'goalkeepers'
    id = db.Column(db.Integer, db.ForeignKey('players.id'), primary_key=True)
    __mapper_args__ = {
        'polymorphic_identity':'goalkeeper'
    }

(Обратите внимание, как это импортирует БД из приложения). Я могу создавать экземпляры этих моделей в своем приложении, создавая экземпляры моделей следующим образом:

db = SQLAlchemy(app)

gk = models.Goalkeeper('John', 'Snow', 1, 1, 3456, 67, 55, 187)
of = models.Outfielder('Gary', 'Lineker', 1, 1, 3999, 77, 78, 176)

db.session.add(gk)
db.session.add(of)
db.session.commit()

Теперь я хотел бы создать экземпляры этих моделей на моем внешнем сотруднике. Единственное, что мешает мне сделать это, это зависимость от моего модуля приложения. Я не чувствую, что эта зависимость оправдана, и хотел бы найти лучший подход к проектированию, чтобы можно было просто экспортировать мой модуль моделей в рабочий и инициализировать экземпляр sqlalchemy, создавать экземпляры моих моделей и сохранять их в базе данных точно так же, как я могу сделать это в самом приложении.

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

db = create_engine(db_url)
metadata = MetaData(db)

print "connection to the database established"

players = Table('players', metadata, autoload=True)
s = players.select()

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

1 ответ

Решение

db.Model такое SQLAlchemy declarative_base(), так что вы можете использовать свои модели, как даже с простой SQLAlchemy.

Этот пример работает (YourModel является моделью Flask-SQLAlchemy):

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

import settings
from models import YourModel

engine = create_engine(settings.SQLALCHEMY_DATABASE_URI)
Session = sessionmaker(bind=engine)    
session = Session()

# do something with your session
session.query(YourModel).first()

Вы должны отделить db от app, так что вы можете импортировать его без запуска app создание, использование db.init_app,

Конечно, вы должны быть осторожны здесь. Если вы загружаете свои настройки динамически, возможно, вы загрузите их не с того места, где import settings вместо current_app.config, но похоже, что вы уже обратились к своему работнику, так что это не проблема для вас.

Другой вариант - создать другое приложение Flask вместо вашего огромного веб-приложения.

Из документов Flask-SQLAlchemy ( http://pythonhosted.org/Flask-SQLAlchemy/api.html):

Вы все еще можете использовать sqlalchemy и sqlalchemy.orm напрямую, но учтите, что настройки Flask-SQLAlchemy доступны только через экземпляр этого класса SQLAlchemy. Классы запросов по умолчанию имеют значение BaseQuery для db.Query, db.Model.query_class и стандартное значение query_class для db.relationship и db.backref. Если вы используете эти интерфейсы напрямую через sqlalchemy и sqlalchemy.orm, классом запросов по умолчанию будет класс sqlalchemy.

РЕДАКТИРОВАТЬ: Еще одна вещь, которую следует помнить при смешивании сеанса sqlalchemy с моделями flask-sqlalchemy, это то, что объект сеанса flask-sqlalchemy на самом деле является подклассом с добавленным словарем _model_changes. Согласно этому ответу, вы не сможете зафиксировать сеанс, если не добавите поле _model_changes:

def create_session(config):
    engine = create_engine(config['DATABASE_URI'])
    Session = sessionmaker(bind=engine)
    session = Session()
    session._model_changes = {}
    return session 
Другие вопросы по тегам