2015-12-15 28 views
6

Chciałbym użyć Flask-Migrate i patrzę na ich przykład:W jaki sposób można podzielić modele Flask z aplikacji app.py bez przerzucania obiektu db?

from flask import Flask 
from flask.ext.sqlalchemy import SQLAlchemy 
from flask.ext.script import Manager 
from flask.ext.migrate import Migrate, MigrateCommand 

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

db = SQLAlchemy(app) 
migrate = Migrate(app, db) 

manager = Manager(app) 
manager.add_command('db', MigrateCommand) 

class User(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(128)) 

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

Działa to doskonale jako prosty przykład grać, ale mogę mieć więcej niż jednego modelu, a ja nie chcę definiować modele zarówno w tym skrypcie, jak i tym, który definiuje mój kod aplikacji. Dlatego chcę je przenieść do pliku modelu, który mogę udostępnić między tymi dwoma.

Próbuję to zrobić, umieszczając klasę User w models.py, a następnie importując użytkownika z tego miejsca. Niestety, to rzuca NameError: name 'db' is not defined.

Moje pytanie (s) są:

  • Czy muszę używać db = SQLAlchemy(app) w moim models.py, a jeśli tak, to będzie dostępne zarówno w moim skrypcie migracji oraz zastosowanie kolby samego?
  • Jeśli nie mogę (lub nie powinienem) umieścić go w models.py, w jaki sposób mogę wykorzystać moje modele w ich własnym pliku bez przekazywania db na całym?
+0

Sprawdź to https://realpython.com/blog/python/python-web-applications-with-flask-part-ii/ – PetarP

Odpowiedz

10

Partycjonowanie tak małej aplikacji w moduły jest trudne, ponieważ znajduje się wiele przypadków, w których dwa tworzone moduły muszą się wzajemnie importować, tworząc okrężne zależności.

Zaleca się sprawdzenie, w jaki sposób można odpowiednio ustrukturyzować większą aplikację, przy użyciu funkcji fabrycznej aplikacji i opóźnionej inicjalizacji wszystkich rozszerzeń. Przykładową aplikacją, która to robi, jest aplikacja Flasky opisana w mojej książce.

Wszystko, co powiedzieliśmy, możliwe jest rozdzielenie aplikacji na dwie części, wystarczy zachować ostrożność przy umieszczaniu instrukcji importowania. W poniższym przykładzie postanowiłem przenieść tworzenie instancji db i modelu User do pliku models.py.

Oto moduł aplikacji głównej:

from flask import Flask 
from flask.ext.script import Manager 
from flask.ext.migrate import Migrate, MigrateCommand 

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

from models import db # <-- this needs to be placed after app is created 
migrate = Migrate(app, db) 

manager = Manager(app) 
manager.add_command('db', MigrateCommand) 

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

A oto modele.py:

from __main__ import app 
from flask.ext.sqlalchemy import SQLAlchemy 

db = SQLAlchemy(app) 

class User(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(128)) 

Tutaj główny moduł stworzy app, a dopiero potem będzie import models.py. Gdy model.py próbuje zaimportować app z modułu głównego, został już utworzony. Jeśli przeniesiesz from models import db na górę pliku z innymi importowanymi, ten kod zostanie zerwany.

+1

Rozumiem twój przykład, ale co, jeśli chcę podzielić models.py na różne pliki .pys? na przykład User.py, Foo.py, Bar.py. Próbuję znaleźć sposób, żeby to zrobić. –

+1

@VitorHugo można utworzyć pakiet 'models', utworzyć instancję' db' w pliku '__init __. Py' pakietu, a następnie dodać jeden moduł na model, przy czym wszystkie te moduły importują instancję' db' jako 'from. import db'. – Miguel

+0

To działało, ale kiedy robię db.create_all() na głównym module aplikacji po "z modeli importu db" nie tworzy on tabel, co dzieje się, gdy robię models.py. Czy to powinno być oddzielne, czy też powinienem się o to martwić? –

0

Oto pomysł. Możesz utworzyć pakiet model, w którym zdefiniujesz klasy jako indywidualne pliki .py. Na przykład user.py zawiera klasę User.

W pliku __init__.py można zdefiniować zmienną db. Możesz również dołączyć instrukcję from user import User, aby móc uzyskać dostęp do obiektu User bezpośrednio poza paczką. Na przykład można zaimportować pakiet model gdzie indziej w programie przy użyciu import model, a następnie użyć model.User do bezpośredniego użycia klasy User.

Aby korzystać db zmienną bezpośrednio w user.py użytku from ..model import db który importuje db zmienną zdefiniowaną w pliku __init__.py.

+0

Czy to nie znaczy, że muszę przekazać 'app' (z' db = SQLAlchemy (app) ') wokół zamiast' db'? – NewGuy

+0

W takim przypadku możesz dodać zarówno 'app', jak i' db' w '__init __. Py' – aliasm2k