Flask-SQLAlchemy içe aktarma / bağlam sorunu


117

Flask uygulamamı şunun gibi yapılandırmak istiyorum:

./site.py
./apps/members/__init__.py
./apps/members/models.py

apps.members bir Flask Blueprint'tir.

Şimdi, model sınıflarını oluşturmak için uygulamayı bir tutmam gerekiyor, örneğin:

# apps.members.models
from flask import current_app
from flaskext.sqlalchemy import SQLAlchemy

db = SQLAlchemy(current_app)

class Member(db.Model):
    # fields here
    pass

Ancak bu modeli Blueprint uygulamama aktarmaya çalışırsam, korkarım RuntimeError: working outside of request context. Uygulamamı buradan nasıl doğru bir şekilde alabilirim? Göreli içe aktarmalar işe yarayabilir ancak oldukça çirkinler ve kendi bağlam sorunları var, örneğin:

from ...site import app

# ValueError: Attempted relative import beyond toplevel package

Yanıtlar:


295

flask_sqlalchemy: Bunun yerine bunu yapabilirsiniz - modül hemen uygulaması ile başlatılması gerekmez

# apps.members.models
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Member(db.Model):
    # fields here
    pass

Ardından, uygulama kurulumunuzda şunları arayabilirsiniz init_app:

# apps.application.py
from flask import Flask
from apps.members.models import db

app = Flask(__name__)
# later on
db.init_app(app)

Bu şekilde, döngüsel içe aktarmalardan kaçınabilirsiniz.

Bu desen yok değil tek dosyada modellerin tüm yerleştirmek gerektirecek. dbDeğişkeni model modüllerinizin her birine aktarmanız yeterlidir .

Misal

# apps.shared.models
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

# apps.members.models
from apps.shared.models import db

class Member(db.Model):
    # TODO: Implement this.
    pass

# apps.reporting.members
from flask import render_template
from apps.members.models import Member

def report_on_members():
    # TODO: Actually use arguments
    members = Member.filter(1==1).all()
    return render_template("report.html", members=members)

# apps.reporting.routes
from flask import Blueprint
from apps.reporting.members import report_on_members

reporting = Blueprint("reporting", __name__)

reporting.route("/member-report", methods=["GET","POST"])(report_on_members)

# apps.application
from flask import Flask
from apps.shared import db
from apps.reporting.routes import reporting

app = Flask(__name__)
db.init_app(app)
app.register_blueprint(reporting)

Not: Bu, size sağladığı gücün bir kısmının bir taslağıdır - geliştirmeyi daha da kolaylaştırmak için yapabileceğiniz biraz daha fazla şey var (bir create_appkalıp kullanarak , belirli klasörlere otomatik kayıt planları, vb.)


2
Bunu birden çok kez yapabilir misin? Örneğin, birden fazla models.py dosyam varsa?
Brad Wright

@BradWright - sahip olduğunuz dbher veritabanı için yalnızca örnek oluşturmanızı kolaylaştırır . Bir model paketiniz varsa içine koyabilirsiniz __init__.py. Ancak bunu yapmayı seçerseniz, dbdeğişkeni o konumdan diğer model dosyalarınıza aktarmanız ve normal şekilde kullanmanız yeterlidir . Yüklendiklerinde her şey doğru şekilde çözülür.
Sean Vieira

1
Bu şekilde kurulmuş bir projeye bir bağlantınız olur mu?
Mbrevda

4
@Mbrevda - bu kalıbın bir örneğini burada görebilirsiniz github.com/svieira/Budget-Manager
Sean Vieira

1
.ext.Ad kullanımdan kaldırıldı - bu gerçek ad aktarılabilecek daha iyidir ( flask_sqlalchemy).
Sean Vieira

25

orijinal bir app.py : https://flask-sqlalchemy.palletsprojects.com/en/2.x/quickstart/

...

app = flask.Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = flask.ext.sqlalchemy.SQLAlchemy(app)

class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
...

class Computer(db.Model):
    id = db.Column(db.Integer, primary_key=True)
...

# Create the database tables.
db.create_all()

...

# start the flask loop
app.run()

Blueprint kullanmadan bir app.py'yi app.py ve model.py olarak böldüm. Bu durumda, yukarıdaki cevap işe yaramaz. Çalışmak için bir satır kodu gereklidir.

önce :

db.init_app(app)

sonra :

db.app = app
db.init_app(app)

Ve aşağıdaki bağlantı çok kullanışlıdır.

http://piotr.banaszkiewicz.org/blog/2012/06/29/flask-sqlalchemy-init_app/


2
db.app = appinit_app uygulamayı ayarlamadığı için çalışma zamanı hatası alıyordu. +1
Amit Tripathi

3
db.app = app(ardından db.init_app(app)) benim için eksik parçaydı. Bu satırı ekledikten sonra mükemmel çalışıyor (Sean Vieira'nın cevabı ile birlikte)
Dotl

İlk bağlantı güncel değil.
Rahul KP
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.