Как создать повторно используемый компонент с помощью Flask-SQLAlchemy?

Допустим, у меня есть часть моего приложения Flask, которую я хочу использовать в нескольких разных проектах. Он имеет модели SQLAlchemy, использующие Flask-SQLAlchemy, а также представления и шаблоны. Я могу получить декораторы app.route с помощью модуля, но как мне обработать объект базы данных SQLAlchemy?

Поскольку мой компонент должен быть отдельным, я не могу просто импортировать объект db. Но я не думаю, что мне следует дважды создавать объект db. Как мне смешать его метаданные с метаданными в остальной части проекта?


person Nick Retallack    schedule 25.04.2011    source источник


Ответы (2)


Сначала вы должны поделиться metadata и не использовать flask-sqlalchemy db.Model в качестве базы для вашего многократно используемого приложения.

Во-вторых, вы должны пересоздать все классы, расширив их новыми базами из flask-sqlalchemy для поддержки сигналов, сокращений и прочего.

Интегрировать базы (может глючить):

def integrate_models(cls, nbase):
        new_bases = list(cls.__bases__) + [nbase]
        new_dict = dict(cls.__dict__)
        new_dict.update(dict(nbase.__dict__))
        return type.__new__(cls.__class__, cls.__name__, tuple(new_bases), new_dict)

Пример приложения Flask с расширением sqlalchemy:

# -*- coding: utf-8 -*-
from flask import Flask
from flaskext.sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)

    def __init__(self, username, email):
        self.username = username
        self.email = email

    def __repr__(self):
        return '<User %r>' % self.username

if __name__ == '__main__':
        from some_model_base import init_metadata
        init_metadata(db.Model.metadata)

        from some_model import SomeClass

        SomeClass = integrate_models(SomeClass, db.Model)

        db.create_all()

        print SomeClass.query.all()

Где some_model_base.py:

from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

def init_metadata(metadata):
    Base.metadata = metadata

И some_model.py:

from sqlalchemy import Column, Integer, String
from some_model_base import Base

class SomeClass(Base):
    __tablename__ = 'some_table'
    id = Column(Integer, primary_key=True)
    name =  Column(String(50))

В этом примере проверены только ярлыки db.create_all и SomeClass.query.

Извините за мой плохой английский.

person estin    schedule 26.04.2011
comment
Хм, мне нужно попробовать это. Можете ли вы найти способ настроить модели в другом модуле, чтобы иметь связь с моделями в основной программе? - person Nick Retallack; 27.04.2011
comment
Я думаю, что лучший способ сделать это - объявить в своем многоразовом приложении базовые классы или MixIns, а затем построить конкретные модели, подклассировав их. - person estin; 28.04.2011

Вы должны использовать flask.current_app, это прокси-объект для доступа к текущему приложению, и это то, что используется в некоторых расширениях. Итак, ваш код будет выглядеть примерно так:

from flask import current_app
from flaskext.sqlalchemy import SQLAlchemy

db = SQLAlchemy(current_app)

а затем используйте свой объект db, как обычно. Но я не уверен, что это сработает, если пользователь использует ваш модуль, а также должен использовать flaskext.sqlalchemy, возможно, это будет конфликтовать, я бы посоветовал проверить это, чтобы убедиться, что ваш модуль будет на 100% совместим с любым приложением flask .

person mdeous    schedule 15.08.2011