Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/api/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 避免将应用程序工厂导入需要应用程序上下文的模块_Python_Api_Flask_Flask Restful - Fatal编程技术网

Python 避免将应用程序工厂导入需要应用程序上下文的模块

Python 避免将应用程序工厂导入需要应用程序上下文的模块,python,api,flask,flask-restful,Python,Api,Flask,Flask Restful,这个问题是我上一个问题的延伸。有人建议我用更多的话来解释这个问题。正如标题所述,我试图找到一种方法来避免将应用程序工厂(创建应用程序函数)导入到需要应用程序上下文的模块中,并且“将当前应用程序导入为应用程序”是不够的 我的问题是我有一个循环导入问题,因为我需要通过这个create\u app函数来获取app\u上下文 在我的\uuuu ini\uuuuu.py中,我有以下内容: # application/__init__.py from flask import Flask from fla

这个问题是我上一个问题的延伸。有人建议我用更多的话来解释这个问题。正如标题所述,我试图找到一种方法来避免将应用程序工厂(创建应用程序函数)导入到需要应用程序上下文的模块中,并且“将当前应用程序导入为应用程序”是不够的

我的问题是我有一个循环导入问题,因为我需要通过这个
create\u app
函数来获取app\u上下文

在我的
\uuuu ini\uuuuu.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
因为在该模块中,我有:

#application/resources/offer.py 

from flask_restful import Resource
from application.models.offer import OfferModel  # IMPORTING OFFER MODEL
然后导入应用程序/models/offer.py,其中我有关键部分:

#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 import current_app as app的
来获取上下文,但没有成功。我不知道为什么将当前应用程序作为应用程序传递并获取上下文是不够的,因为它现在迫使我通过创建应用程序工厂,这导致了循环导入问题。

您的
更新\u offer\u price
方法需要数据库交互和访问配置。它从应用程序上下文中获取它们,但它仅在
Flask
应用程序初始化时起作用。此方法在单独的线程中运行,因此您可以在此线程中创建
Flask
应用程序的第二个实例

另一种方法是在应用程序上下文之外获得独立的数据库交互和配置访问

配置 当应用程序从另一个模块获取配置时,配置似乎没有问题:

app.config.from_object("config.Config")
因此,您可以直接将此对象导入您的
offer.py

from config import Config

headers = {"Bearer": Config.MS_API_ACCESS_TOKEN}
数据库访问 要获得独立的数据库访问,您需要通过
SQLAlchemy
而不是
flask\u SQLAlchemy
定义模型。这篇文章已经描述过了,但我在这里发布了要点。你的情况可能是这样的。您的
base.py
模块:

from sqlalchemy import MetaData
from sqlalchemy.ext.declarative import declarative_base

metadata = MetaData()
Base = declarative_base(metadata=metadata)
import sqlalchemy as sa

from .base import Base

class OfferModel(Base):
    id = sa.Column(sa.Integer, primary_key=True)
    # Another declarations
offer.py
模块:

from sqlalchemy import MetaData
from sqlalchemy.ext.declarative import declarative_base

metadata = MetaData()
Base = declarative_base(metadata=metadata)
import sqlalchemy as sa

from .base import Base

class OfferModel(Base):
    id = sa.Column(sa.Integer, primary_key=True)
    # Another declarations
生成的
元数据
对象用于初始化您的
flask\u sqlalchemy
对象:

from flask_sqlalchemy import SQLAlchemy

from application.models.base import metadata

db = SQLAlchemy(metadata=metadata)
可以在应用程序上下文之外查询模型,但需要手动创建数据库引擎和会话。例如:

from sqlalchemy import create_engine
from sqlalchemy.orm import Session

from config import Config

from application.models.offer import Offer

engine = create_engine(Config.YOUR_DATABASE_URL)
# It is recommended to create a single engine
# and use it afterwards to bind database sessions to.
# Perhaps `application.models.base` module
# is better to be used for this declaration.

def your_database_interaction():
    session = Session(engine)
    offers = session.query(Offer).all()
    for offer in offers:
        # Some update here
    session.commit()
    session.close()
请注意,使用这种方法,您不能使用模型类进行查询,我的意思是:

OfferModel.query.all()  # Does not work
db.session.query(OfferModel).all()  # Works

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

# 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

它不是很漂亮,但很管用。

uuuh。我不知道我是否理解,但好的,非常感谢。我会再读五遍,也许我会得到它。。。这看起来不是一个很小的问题顺便说一句,我可以通过将我的“.import Offer,Offers”与“api.add_resource()”放在init.py中的create_app()之后来解决这个问题。这是一种黑客行为,但这种方式没有循环导入:-)你对此有何看法?好吧,我理解这是架构上的一个相当大的变化,特别是在最初的问题之后,只提出了几个问题行:)你的解决方案解决了你的问题,所以它是好的。我不知道在向应用程序添加更多逻辑后,它是否能正常工作。但是你应该把它作为你问题的答案,这是一个很好的做法,所以:)