I wanna do a POST request on an flask app like this:
def create_app():
app = Flask(__name__)
with app.app_context():
c = Config('cfg.cfg')
abc = Abc(c)
return app
app = create_app()
#app.route('/', methods=['POST'])
def handle_webhook():
return abc.handle_incoming_hook(request)
but is gives me error: abc is undefined.
Is there anything I was missing?
The variable abc is being declared outside of the scope of your handle_webhook function. You will either need to pass abc in to the handle_webhook function, or declare it within the scope of the handle_webhook function.
Related
i am trying to generate Flask route using a basic DI i.e mapping methods as route handlers, i am a total beginner at Flask so mind my basic skills
class myClass():
def __init__(self):
self.dbConnObj = DbToolsMySql('someconnection', 'slave')
self.dbConnObj.connect()
self.blueprint = Blueprint('myClass', __name__)
self.blueprint.add_url_rule('/my_method', view_func=self.my_method)
def my_method(self, event):
retun "hello"
and then in my handler file
from flask import Flask
from flask_restful import Api, Resource
from src.app.services.myClassimport myClass
app = Flask(__name__)
app.register_blueprint(myClass.blueprint)
if __name__ == "main":
app.run()
Quite simple ehh???? but not working... i am getting following message
Not Found The requested URL was not found on the server. If you
entered the URL manually please check your spelling and try again.
typically you add routes to the Flask app with decorators like so:
app = Flask(__name__)
#app.route('/some-endpoint')
def some_endpoint_handler():
# do something
pass
Or you can add without a decorator like so:
def some_endpoint_handler():
# do something
pass
app = Flask(__name__)
app.route('/some-endpoint', methods=['GET'])(some_endpoint_handler)
So in your scenario, you can pass the app.route call to your myClass object and set the route like this:
class myClass():
def __init__(self, router):
self.dbConnObj = DbToolsMySql('someconnection', 'slave')
self.dbConnObj.connect()
self.blueprint = Blueprint('myClass', __name__)
#self.blueprint.add_url_rule('/my_method', view_func=self.my_method)
router('/my_method', ['GET'])(self.my_method)
def my_method(self, event):
retun "hello"
myObj = myClass( app.route )
or, invert the dependency:
app = Flask(__name__)
#app.route(myClass.blueprint.some_endpoint_string)
def some_endpoint_handler():
myClass.blueprint.call_some_endpoint_handler()
pass
if __name__ == "main":
app.run()
the docs suggest using factory function.
def create_app():
app = Flask(__name__)
return app()
so I don't have access to my app when I'm writing my code,
for this porpuse there is an object called " current_app " in flask module,
so I did this and I got " out of application context error "
#current_app.before_request
def before_req():
whatever...
how can I define before request functions when I'm using a factory function?!
You can define your before_request function inside create_app function:
def create_app():
app = Flask(__name__)
#app.before_request
def before_request(response):
response.headers['Access-Control-Allow-Origin'] = '*'
return response
return app
If you use Flask Blueprints, you define before_request function for your blueprint like this:
from Flask import Blueprint
my_blueprint = Blueprint('my_blueprint', __name__)
#my_blueprint.before_request
def before_request(response):
response.headers['Access-Control-Allow-Origin'] = '*'
return response
I'm trying to define some global constants for my app, and have found that this can be done with a function that's decorated as #app.context_processor.
However, the issue is that I don't have an app variable. My application uses an application factory, and I'd like to keep it that way. Is there a different way to register a function as the context_processor for my app?
One option I have seen is to apply the decorator to each Blueprint instead of applying it to the app. That's something I would like to avoid though, since it would lead to a lot of duplicate code.
The issue is that there is no app object in case of factories. You have a create_app function where the app gets created.
So to install the context processors you can use create_app itself
def create_app(config_filename):
app = Flask(__name__)
app.config.from_pyfile(config_filename)
from yourapplication.model import db
db.init_app(app)
from yourapplication.context_processor import myprocessor
app.context_processor(myprocessor)
from yourapplication.views.frontend import frontend
app.register_blueprint(frontend)
return app
You could also have the function in the same app.py file (wherever the create_app() function is written). In such a case, you could simply register the context_processor without importing it.
Another approach is to do it in a blueprint as shown in below
Flask context processors functions
from flask import Blueprint
thingy = Blueprint("thingy", __name__, template_folder='templates')
#thingy.route("/")
def index():
return render_template("thingy_test.html")
#thingy.context_processor
def utility_processor():
def format_price(amount, currency=u'$'):
return u'{1}{0:.2f}'.format(amount, currency)
return dict(format_price=format_price)
my source code has this structure:
main.py:
from flask import Flask, g
app = Flask(__name__)
with app.app_context():
g.my_db = PostgreSQL()
app.register_blueprint(my_app, url_prefix="/my_app")
my_app.py:
from flask import Blueprint, g
my_app = Blueprint("my_app", __name__)
#my_app.route("/")
def index():
return g.my_db.fetch_all() <<< ERROR
but it shows this error:
AttributeError: '_AppCtxGlobals' object has no attribute 'my_db'
Even when I try to use g outside of app context, it shows this error:
RuntimeError: Working outside of application context.
So how to set and access to global variables in Flask?
This happens because the data are lost when the context (with app.app_context()) ends (doc).
Inside the context, everything is ok :
from flask import Flask, g
app = Flask(__name__)
with app.app_context():
g.my_db = 'database ok'
print(g.my_db)
# >>> this prints 'database ok'
But outside, you cannot access the attribute :
from flask import Flask, g
app = Flask(__name__)
with app.app_context():
g.my_db = 'database ok'
print(g.my_db)
# >>> this throws RuntimeError: Working outside of application context
even if you create a new context:
from flask import Flask, g
app = Flask(__name__)
with app.app_context():
g.my_db = 'database ok'
with app.app_context():
print(g.my_db)
>>> this throws AttributeError: '_AppCtxGlobals' object has no attribute 'my_db'
Your best call should be to declare the database object before the context, and then import it. Or maybe you can create it directly inside my_app.py where you need it ?
g isn't persistent in the way you're trying to use it. Write a function to create a connection each time you need it. Preferably use a database extension like Flask-SQLAlchemy to manage connections for you.
db.py:
import <postgresql dependencies>
def get_db():
db = PostgreSQL()
# config here
return db
main.py:
from flask import Flask
app = Flask(__name__)
app.register_blueprint(my_app, url_prefix="/my_app")
my_app.py:
from flask import Blueprint, g
from db import get_db
my_app = Blueprint("my_app", __name__)
#my_app.route("/")
def index():
db = get_db()
data = db.fetch_all()
db.close()
return data
I'm learning Flask and am a bit confused about how to structure my code. So I tried to extend Flask main class as follows:
from flask import Flask, ...
class App(Flask):
def __init__(self, import_name, *args, **kwargs):
super(App, self).__init__(import_name, *args, **kwargs)
Note that I am aware of that this may be a completely wrong approach.
So that when I want to start the app I do:
app = App(__name__)
if __name__ == '__main__':
app.run()
This way I can order my methods and routes in the class, but the problem is when using self-decorators:
#route('/')
def home(self, context=None):
context = context or dict()
return render_template('home.html', **context)
Which raises an error as unresolved reference 'route'. I guess this is not the way I should be structuring the app. How should I do it instead or how do I get the error fixed?
Doing this doesn't make sense. You would subclass Flask to change its internal behavior, not to define your routes as class methods.
Instead, you're looking for blueprints and the app factory pattern. Blueprints divide your views into groups without requiring an app, and the factory creates and sets up the app only when called.
my_app/users/__init__.py
from flask import Blueprint
bp = Blueprint('users', __name__, url_prefix='/users')
my_app/users/views.py
from flask import render_template
from my_app.users import bp
#bp.route('/')
def index():
return render_template('users/index.html')
my_app/__init__.py
def create_app():
app = Flask(__name__)
# set up the app here
# for example, register a blueprint
from my_app.users import bp
app.register_blueprint(bp)
return app
run.py
from my_app import create_app
app = create_app()
Run the dev server with:
FLASK_APP=run.py
FLASK_DEBUG=True
flask run
If you need access to the app in a view, use current_app, just like request gives access to the request in the view.
from flask import current_app
from itsdangerous import URLSafeSerializer
#bp.route('/token')
def token():
s = URLSafeSerializer(current_app.secret_key)
return s.dumps('secret')
If you really want to define routes as methods of a Flask subclass, you'll need to use self.add_url_rule in __init__ rather than decorating each route locally.
class MyFlask(Flask):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.add_url_rule('/', view_func=self.index)
def index(self):
return render_template('index.html')
The reason route (and self) won't work is because it's an instance method, but you don't have an instance when you're defining the class.