避免将应用程序工厂导入需要应用程序上下文的模块中 [英] Avoiding importing application factory into module needing application context

查看:48
本文介绍了避免将应用程序工厂导入需要应用程序上下文的模块中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是我上一个此处的扩展.建议我多解释一下这个问题.如标题所述,我正在尝试寻找一种避免将应用程序工厂(create_app函数)导入需要应用程序上下文并将current_app作为应用程序导入"的模块的方法.还不够.

This question is an extension on my previous one here. I was suggested to put more to explain the problem. As the heading says, I am trying to find a way to avoid importing the application factory (create_app function) into a module that needs application context and were "import current_app as app" is not sufficient.

我的问题是由于此 create_app 函数需要循环传递才能获取app_context,因此我遇到了循环导入问题.

My problem is I have a circular import problem due to this create_app function which I need to pass in order to get the app_context.

在我的 __ ini __.py 中,我有这个:

# application/__init__.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_restful import Api
from application.resources.product import Product, Products
from application.resources.offer import Offer, Offers  # HERE IS THE PROBLEM

api = Api()
db = SQLAlchemy()

api.add_resource(Product, "/product/<string:name>")  # GET, POST, DELETE, PUT to my local database
api.add_resource(Products, "/products")  # GET all products from my local database
api.add_resource(Offer, "/offer/<int:id>")  # POST call to the external Offers API microservise
api.add_resource(Offers, "/offers")  # GET all offers from my local database


def create_app(config_filename=None):
    """ Initialize core application. """
    app = Flask(__name__, instance_relative_config=False)
    app.config.from_object("config.Config")

    db.init_app(app)
    api.init_app(app)

    with app.app_context():
        db.create_all()

        return app

问题出在这一行:

from application.resources.offer import Offer, Offers  # HERE IS THE PROBLEM

因为在那个模块中,我有:

because in that module, I have:

#application/resources/offer.py 

from flask_restful import Resource
from application.models.offer import OfferModel  # IMPORTING OFFER MODEL

依次导入 application/models/offer.py ,其中我有关键部分:

which in turn imports application/models/offer.py where I have the critical part:

#application/models/offer.py

import requests
# from flask import current_app as app 
from application import create_app  # THIS CAUSES THE CIRCULAR IMPORT ERROR
from sqlalchemy.exc import OperationalError

app = create_app() # I NEED TO CREATE THE APP IN ORDER TO GET THE APP CONTEXT BECASE IN THE CLASS I HAVE SOME FUNCTIONS THAT NEED IT

class OfferModel(db.Model):
    """ Data model for offers. """
    # some code to instantiate the class... + other methods..

    # THIS IS ONE OF THE METHODS THAT NEED APP_CONTEXT OR ELSE IT WILL ERROR OUT
    @classmethod
    def update_offer_price(cls):
        """ Call offers api to get new prices. This function will run in a separated thread in a scheduler. """
        with app.app_context():
            headers = {"Bearer": app.config["MS_API_ACCESS_TOKEN"]}
            for offer_id in OfferModel.offer_ids:
                offers_url = app.config["MS_API_OFFERS_BASE_URL"] + "/products/" + str(offer_id) + "/offers"
                res = requests.get(offers_url, headers=headers).json()
                for offer in res:
                    try:
                        OfferModel.query.filter_by(offer_id=offer["id"]).update(dict(price=offer["price"]))
                        db.session.commit()
                    except OperationalError:
                        print("Database does not exists.")
                        db.session.rollback()

我尝试使用从flask导入current_app作为app 的烧瓶中获取的上下文,但它不起作用.我不知道为什么不足以将current_app作为应用程序传递并获取上下文,因为它现在迫使我通过create_app应用程序工厂,这会导致循环导入问题.

I have tried to use from flask import current_app as app to get the context, it did not work. I don't know why it was not sufficient to pass current_app as app and get the context because it now forces me to pass the create_app application factory which causes the circular import problem.

推荐答案

好的,这就是我解决的方法.我创建了一个新文件endpoints.py,在其中放置了所有的Api资源

ok so this is how I solved it. I made a new file endpoints.py where I put all my Api resources

# application/endpoints.py    

from application import api
from application.resources.product import Product, Products
from application.resources.offer import Offer, Offers

api.add_resource(Product, "/product/<string:name>")  # GET, POST, DELETE, PUT - calls to local database
api.add_resource(Products, "/products")  # GET all products from local database.
api.add_resource(Offer, "/offer/<int:id>")  # POST call to the Offers API microservice.
api.add_resource(Offers, "/offers")  # GET all offers from local database

然后在init.py中,将其导入到最底部.

Then in init.py I import it at the very bottom.

# aplication/__init__.py

from flask import Flask
from flask_restful import Api
from db import db

api = Api()


def create_app():
    app = Flask(__name__, instance_relative_config=False)
    app.config.from_object("config.Config")
    db.init_app(app)
    api.init_app(app)
    
    with app.app_context():
        from application import routes
        db.create_all()

        return app


from application import endpoints # importing here to avoid circular imports

它不是很漂亮,但是可以.

It is not very pretty but it works.

这篇关于避免将应用程序工厂导入需要应用程序上下文的模块中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆