Подтвердить что ты не робот

Циркулярный импорт ссылки db с использованием Flask-SQLAlchemy и чертежей

Я использую Flask-SQLAlchemy и Blueprints, и я не могу помочь себе использовать циклический импорт. Я знаю, что я могу писать импорт внутри функций и заставить работать, но это звучит неприятно, я бы хотел подтвердить сообщество, если есть лучший способ сделать это.

Проблема заключается в том, что у меня есть модуль (blueprints.py), где я объявляю базу данных и импортирую чертежи, но эти чертежи должны одновременно импортировать объявление базы данных.

Это код (выдержка из важных частей):

application.apps.people.views.py

from application.blueprints import db

people = Blueprint('people', __name__,
                 template_folder='templates',
                 static_folder='static')

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

@people.route('/all')
def all():
    users = User.query.all()

application.blueprints.py

from application.apps.people.views import people

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

Я прочитал документацию и вопросы, которые я нашел по этой теме, но я все еще не могу найти ответ, который я ищу. Я нашел эту главу (https://pythonhosted.org/Flask-SQLAlchemy/contexts.html), где предлагается поместить код инициализации внутри метода, но циклический импорт все еще сохраняется.

Edit Я исправил проблему, используя шаблон Приложение Factory

4b9b3361

Ответ 1

Я исправил проблему с помощью Application Factory. Я объявляю базу данных в третьем модуле и настраиваю ее позже в том же модуле, в котором я запускаю приложение.

Это приводит к следующим импортам:

  • database.py → app.py
  • views.py → app.py
  • database.py → views.py

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

Вот пример приложения:

app.py

from database import db
from flask import Flask
import os.path
from views import User
from views import people


def create_app():
    app = Flask(__name__)
    app.config['DEBUG'] = True
    app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:////tmp/test.db"
    db.init_app(app)    
    app.register_blueprint(people, url_prefix='')
    return app 


def setup_database(app):
    with app.app_context():
        db.create_all()
    user = User()
    user.username = "Tom"
    db.session.add(user)
    db.session.commit()    


if __name__ == '__main__':
    app = create_app()
    # Because this is just a demonstration we set up the database like this.
    if not os.path.isfile('/tmp/test.db'):
      setup_database(app)
    app.run()

database.py

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

views.py

from database import db
from flask.blueprints import Blueprint


people = Blueprint('people', __name__,
                 template_folder='templates',
                 static_folder='static')


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


@people.route('/')
def test():
  user = User.query.filter_by(username="Tom").first()
  return "Test: Username %s " % user.username

Ответ 2

Циркулярный импорт в колбе приводит меня в орехи. Из документов: http://flask.pocoo.org/docs/0.10/patterns/packages/

... Имейте в виду, что это плохая идея в целом, но здесь она на самом деле прекрасна.

Это не нормально. Глубоко неправильно. Я также считаю, что любой код в __init__.py является плохой практикой. Это делает приложение сложнее масштабировать. Чертежи - это способ облегчить проблему с помощью циркулярного импорта. Я думаю, что Флану нужно больше этого.

Ответ 3

Серж, выведите определение моделей в отдельный файл под названием models.py. Запишите проект в файле __init__.py пакета.

У вас есть циклический импорт, потому что файл чертежа пытается импортировать ссылку на людей из views.py, но в views.py вы пытаетесь импортировать db из blueprints.py. И все это делается на верхнем уровне модулей.

Вы можете сделать свою структуру проекта следующим образом:

app
  __init__.py  # registering of blueprints and db initialization
  mods
    __init__.py
    people
      __init__.py  # definition of module (blueprint)
      views.py  # from .models import User
      models.py # from app import db

UPD:

Для тех, кто находится в танке:

people/__init__.pymod = Module('app.mods.people', 'people')

people/views.py@mod.route('/page')

app/__init__.pyfrom app.mods import people; from app.mods.people import views; app.register_blueprint(people.mod, **options);

Ответ 4

Я знаю, что это уже решено, но я решил это немного по-другому и хотел ответить, если это поможет другим.

Первоначально код моего приложения (например, my_app.py) содержал my_app.py строку:

db = SQLAlchemy(app)

И вот в моем models.py меня было:

from my_app import db

class MyModel(db.Model):
    # etc

отсюда циклические ссылки при использовании MyModel в my_app. Я обновил это так, чтобы models.py имел это:

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()  # note no "app" here, and no import from my_app above

class MyModel(db.Model):
    # etc as before

а затем в my_app:

from models import db, MyModel  # importing db is new

# ...

db.init_app(app)  # call init_app here rather than initialising db here