Avoiding Importing Application Factory Into Module Needing Application Context
Solution 1:
Your update_offer_price
method needs database interaction and an access to the configuration. It gets them from the application context but it works only if your Flask
application is initialized. This method is run in a separate thread so you create the second instance of Flask
application in this thread.
Alternative way is getting standalone database interaction and configuration access outside the application context.
Configuration
Configuration does not seem a problem as your application gets it from another module:
app.config.from_object("config.Config")
So you can directly import this object to your offer.py
:
from config importConfigheaders= {"Bearer": Config.MS_API_ACCESS_TOKEN}
Database access
To get standalone database access you need to define your models via SQLAlchemy
instead of flask_sqlalchemy
. It was already described in this answer but I post here the essentials. For your case it may look like this. Your base.py
module:
from sqlalchemy importMetaDatafrom sqlalchemy.ext.declarativeimport declarative_base
metadata = MetaData()
Base = declarative_base(metadata=metadata)
And offer.py
module:
import sqlalchemy as sa
from .base import Base
classOfferModel(Base):
id = sa.Column(sa.Integer, primary_key=True)
# Another declarations
The produced metadata
object is used to initialize your flask_sqlalchemy
object:
from flask_sqlalchemy importSQLAlchemyfrom application.models.baseimport metadata
db = SQLAlchemy(metadata=metadata)
Your models can be queried outside the application context but you need to manually create database engine and sessions. For example:
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.defyour_database_interaction():
session = Session(engine)
offers = session.query(Offer).all()
for offer in offers:
# Some update here
session.commit()
session.close()
Note that with this approach you can't use your models classes for queriing, I mean:
OfferModel.query.all() # Does not work
db.session.query(OfferModel).all() # Works
Solution 2:
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
Then in init.py I import it at the very bottom.
# aplication/__init__.pyfrom flask import Flask
from flask_restful import Api
from db import db
api = Api()
defcreate_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.
Post a Comment for "Avoiding Importing Application Factory Into Module Needing Application Context"