Ich habe eine Lauf Flask-Anwendung, die wir online gefunden nach einer Kombination bewährter Verfahren eingerichtet ist und in Miguel Grinberg des „Flask Web Development“ Buch.Teile sqlalchemy Modelle zwischen Kolben und anderen Anwendungen
Wir brauchen jetzt eine zweite Python-Anwendung, die KEINE Web-App ist und Zugriff auf die gleichen Modelle wie die Flask-Anwendung benötigt. Wir wollten dieselben Modelle wiederverwenden, sodass beide Apps vom gemeinsamen Code profitieren können.
Wir haben Abhängigkeiten auf dem Kolben-sqlalchemy extention entfernt (die wir vorher benutzt, wenn wir nur die Flasche Anwendung hatte). Und ersetzt es durch die SQLalchemy Declarative extension described here, die ein bisschen einfacher ist (Flask-SQLalchemy adds a few specific things to standard SQLAlchemy)
In Übereinstimmung mit dem Beispiel haben wir eine Datei datenbank.py im Stamm erstellt. In unserem Fall gibt es zwei Dinge, die sich von der deklarative Erweiterung Beispiel: ich den Motor und Sitzung in einer Klasse setzen, weil alle unsere Modelle db.session verwenden, statt db_session, und gebe ich ein Wörterbuch mit Konfigurationswerten zum init(), damit ich dieses database.py sowohl von Flask als auch von einer anderen Anwendung mit einer anderen Konfiguration wiederverwenden kann. es sieht so aus:
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()
So jetzt kommen wir zum eigentlichen Problem. Flask erstellt ein wörterbuchähnliches Objekt, das Konfigurationsoptionen enthält, und fügt sie als Eigenschaft der App-Instanz hinzu. Es lädt sie aus einem instance folder, einem config.py im Stammverzeichnis der Site und von Umgebungsvariablen. Ich muss das Konfigurationswörterbuch von Flask übergeben, also brauche ich FLASK, um zuerst die Konfiguration zu laden und zu assemblieren, danach die Datenbank zu initialisieren und ein (konfiguriertes) db-Objekt im Stamm der App-Datei zu haben. Wir folgen jedoch der Application factory pattern, so dass wir verschiedene Konfigurationen für verschiedene Situationen (Test, Produktion, Entwicklung) verwenden können.
Dies bedeutet, dass unsere app/__init__.py
etwa wie folgt aussieht (vereinfacht):
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
Aber die db (dass die Modelle importieren aus ..), muss nun innerhalb der create_app() Funktion, denn das ist, wo Der Kolben lädt die Konfiguration. Wenn ich das db -Objekt außerhalb der Funktion create_app() instanziieren würde, könnte es aus den Modellen importiert werden, aber es ist nicht konfiguriert!
ein Beispiel Modell wie folgt aussieht, und wie man sehen kann, erwartet er einen „db“ in der Wurzel der App:
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')
Also meine Frage ist, wie kann ich eine DB-Instanz, kann extern konfiguriert werden (entweder mit Flask oder einer anderen App) und weiterhin das Application Factory Pattern verwenden?
bearbeiten: Das Codebeispiel war falsch, es hatte einen Import für Flask-SQLalchemy, die durch from database import Database
ersetzt wurde. Entschuldigung für jede Verwirrung.
Die Teardown-Funktion, ruft 'db.session.remove' unnötig und kann tatsächlich zu Problemen führen. – davidism
Die Teardown-Funktion benötigt die Declarative-Methode gemäß der Flask-Dokumentation: http://flask.pocoo.org/docs/0.10/patterns/sqlalchemy/ –
Da es sich um eine Scoped-Sitzung handelt, ist das nur überflüssig. Danke, dass du das herausgebracht hast, aber ich muss diese Dokumente reparieren. – davidism