Mam uruchomioną aplikację Flask, która została skonfigurowana zgodnie z najlepszą praktyką znalezioną online oraz w książce "Flask Web Development" autorstwa Miguela Grinberga.Udostępnianie modeli sqlalchemy między kolbą a innymi aplikacjami
Potrzebujemy teraz drugiej aplikacji Pythona, która NIE jest aplikacją internetową i wymaga dostępu do tych samych modeli co aplikacja Flask. Chcieliśmy ponownie wykorzystać te same modele, więc obie aplikacje mogą korzystać ze wspólnego kodu.
Usunęliśmy zależności na rozszerzeniu kolby-sqlalchemy (którego używaliśmy wcześniej, kiedy mieliśmy tylko aplikację Flask). Zastąpiono go numerem SQLalchemy Declarative extension described here, który jest nieco prostszy (Flask-SQLalchemy adds a few specific things to standard SQLAlchemy). W naszym przypadku są dwie rzeczy różne od Deklaratywnego przykładu rozszerzenia: umieszczam silnik i sesję w klasie, ponieważ wszystkie nasze modele używają db.session, zamiast db_session, i przekazuję słownik z wartościami konfiguracji do init(), dzięki czemu mogę ponownie użyć tego pliku database.py zarówno z Flask, jak i innej aplikacji, używając innej konfiguracji. to wygląda tak:
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
class Database(object):
def __init__(self, cfg):
self.engine = create_engine(cfg['SQLALCHEMY_DATABASE_URI'], convert_unicode=True)
self.session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=self.engine))
class Model(object):
pass
Base = declarative_base()
Teraz dochodzimy do rzeczywistego problemu. Flask tworzy obiekt słownikowy zawierający opcje konfiguracji i dodaje je jako właściwość do instancji aplikacji. Ładuje je z katalogu instance folder, config.py w katalogu głównym witryny i ze zmiennych środowiskowych. Muszę przekazać w słowniku konfiguracji z Flask, więc potrzebuję Flask do PIERWSZEGO załadowania i złożenia konfiguracji, a następnie zainicjować bazę danych i mieć (skonfigurowany) obiekt db w katalogu głównym pliku aplikacji. Jednak podążamy za Application factory pattern, dzięki czemu możemy korzystać z różnych konfiguracji dla różnych sytuacji (test, produkcja, rozwój).
Oznacza to nasza app/__init__.py
wygląda mniej więcej tak (uproszczony):
from flask import Flask
from database import Database
from flask.ext.mail import Mail
from flask_bcrypt import Bcrypt
from config import config
mail = Mail()
bcrypt = Bcrypt()
def create_app(config_name):
app = Flask(__name__, instance_relative_config=True)
if not config_name:
config_name = 'default'
app.config.from_object(config[config_name])
app.config.from_pyfile('config.py')
config[config_name].init_app(app)
db = Database(app.config)
mail.init_app(app)
bcrypt.init_app(app)
@app.teardown_appcontext
def shutdown_session(exception=None):
db.session.remove()
from main import main as main_blueprint
app.register_blueprint(main_blueprint)
return app
Ale dB (że modele importować z ..), teraz musi być wewnątrz funkcji create_app(), bo tam Kolba ładuje konfigurację. Jeśli chciałbym utworzyć instancję obiektu db poza funkcją create_app(), będzie można ją importować z modeli, ale nie jest ona skonfigurowana!
przykładem modelu wygląda to i tak widać, że spodziewa się „db” w katalogu głównym aplikacji:
from . base_models import areas
from sqlalchemy.orm import relationship, backref
from ..utils.helper_functions import newid
from .. import db
class Areas(db.Model, areas):
"""Area model class.
"""
country = relationship("Countries", backref=backref('areas'))
def __init__(self, *args, **kwargs):
self.area_id = newid()
super(Areas, self).__init__(*args, **kwargs)
def __str__(self):
return u"{}".format(self.area_name).encode('utf8')
def __repr__(self):
return u"<Area: '{}'>".format(self.area_name).encode('utf8')
Więc moje pytanie brzmi, jak mogę mieć wystąpienie db że mogą być konfigurowane zewnętrznie (przez Flask lub inną aplikację) i nadal używać Wzorca Fabrycznego Aplikacji?
edit: Kod-przykładem była błędna, to miał import dla skrzynkowego sqlalchemy który został zastąpiony przez from database import Database
. Przepraszamy za jakiekolwiek zamieszanie.
Funkcja porzuca który wywołuje 'db.session.remove' jest niepotrzebne i może rzeczywiście powodować problemy. – davidism
Funkcja ta jest niedostępna przy użyciu metody Deklaratywnej, zgodnie z dokumentacją Flask: http://flask.pocoo.org/docs/0.10/patterns/sqlalchemy/ –
Ponieważ jest to sesja z zakresem, jest to po prostu zbędne. Dziękuję za wskazanie tego, ale muszę naprawić te dokumenty. – davidism