I have just started with Flask I know django. We take a request parameter in a simple django view
from django.http import HttpResponse
def view(request):
#request is the local paramter for view
return HttpResponse('Welcome to Django')
Now this view is request aware because of parameter passed.
But now in Flask
from flask import Flask, request
app = Flask(__name__)
#app.route('/', methods=['GET','POST'])
def view():
if request.method == 'GET':
return "Hello from Flask"
request is not local to function view how it is aware of the request it should be like request is not defined.
Where it is coming from?
How it works here?
EDIT
I thought decorator is doing that
Decorator works this way
def deco(f):
def declare_x():
global x
x=9
f()
return declare_x
#deco
def do_it():
print(x)
do_it()
But I did not see any global reference at flask repo
and I dont think it is implemented like this here.
Please help me understand how it is working.Thanks in advance.
Related
My question is, can an endpoint in a Flask API call a method from another endpoint, that is a member of itself? Is there a proper way of doing this?
Yes, you can indeed call another endpoint by using redirect with url_for
If this is something you are trying to achieve.
from flask import Flask, redirect, url_for
app = Flask(__name__)
#app.route('/')
def hello_world():
return "Hello world"
#app.route('/home')
def hello_again():
return redirect(url_for('.hello_world'))
if __name__=="__main__":
app.run(debug=True)
The request to /home will redirect you to /.
I have a Flask app with blueprints. It worked just fine, but than I decided to use flask_jwt_extended to handle tokens. It is said in docs that I can decorate method with jwt.user_lookup_loader to have current_user working. But for some reason calling current_user ends up with an error:
You must provide a `#jwt.user_lookup_loader` callback to use this method
But it is there, in the same blueprint. There is also a method, decorated with #jwt.user_identity_loader and it works perfectly well.
Here is a simplified version of my code:
from . import rpc, jwt
from flask_jwt_extended import current_user, jwt_required
bp = Blueprint('login_bp', __name__)
#jwt.user_identity_loader
def _user_identity_lookup(user):
return user.id
#jwt.user_lookup_loader
def _user_lookup_callback(_jwt_header, jwt_data):
identity = jwt_data["sub"]
user = rpc.cache_service.get_user(identity)
if user is None:
return None
return UserSchema().load(user)
#jwt_required()
#bp.route("/logout", methods=['POST'])
def logout():
rpc.cache_service.forget_user(current_user.id)
return {"status": "OK"}
jwt here is JWTManager, initialized with my app:
jwt = JWTManager()
def create_app():
app = Flask(__name__, instance_relative_config=False)
app.config.from_mapping(JWT_SECRET_KEY=os.environ["JWT_SECRET_KEY"])
...
jwt.init_app(app)
...
with app.app_context():
from . import login_bp
app.register_blueprint(login_bp.bp)
This code is basicly from the documentation examples:
https://flask-jwt-extended.readthedocs.io/en/stable/automatic_user_loading/
and I can't see what the problem might be (
Link to the repo:
https://github.com/GreenBlackSky/COIN/blob/master/api_app/app/login_bp.py
Your decorators are in the wrong order. #bp.route() needs to come before #jwt_required(), otherwise it tries to evaluate the logout method when a request comes in before it decodes the JWT in the request.
I have a blueprint and some url functions,
admin_bp = Blueprint('admin', __name__)
#admin_bp.route('/dashboard', methods=['GET', ])
#flask_login.login_required
def dashboard():
context = {}
page = 'admin/dashboard.html'
return render_template(page, **context)
#admin_bp.route('/deny', methods=['GET', ])
#flask_login.login_required
def deny():
return 'hey bro you dont belong here'
I don't want to copy paste #flask_login.login_required decorator for all url functions under this blueprint. Is there a better way that I can apply decorator for all blueprint urls?
You can add before_request() as a function that will run before each request in a view.
You will then want to add decorators to inject additional functionality to the before_request function. You will want to import the login_required decorator to ensure each endpoint requires a logged in user. This decorator is part of the flask_login library.
Since it looks like your views are part of an admin, I'd also recommend adding a custom decorator to your before_request function with something like #role_required('admin'). The functionality for that decorator will live somewhere else and be imported.
#admin_bp.before_request
#login_required
def before_request():
""" Protect all of the admin endpoints. """
pass
Subclass Blueprint and override the route method.
import flask
class MyBlueprint(flask.Blueprint):
def route(self, rule, **options):
def decorator(f):
# these lines are copied from flask.Blueprint.route
endpoint = options.pop("endpoint", f.__name__)
self.add_url_rule(rule, endpoint, f, **options)
# At this point flask.Blueprint.route simply returns f.
# But you can nest a decorator.
def inner(*args, **kwargs):
# stuff you want to do before each request goes here
try:
result = f(*args, **kwargs)
# stuff you want to do on successful responses (probing status, headers, etc.) goes here
except Exception as e:
# stuff you want to do on error responses goes here
raise
return inner
Now use the new subclass in your blueprints:
-v1_blueprint = Blueprint('v1', __name__)
+v1_blueprint = MyBlueprint('v1', __name__)
No changes needed to individual routes.
The drawback of this approach is that it copies code from inside Flask. If the implementation of flask.Blueprint.route were to change in a future version, you'd need to sync MyBlueprint with it when you upgrade Flask.
How about checking the user first:
from flask.ext.login import current_user
#admin_bp.before_request
def check_user():
if not current_user.is_authenticated():
abort(401)
# your other functions without `#flask_login.login_required`
I inherited a project that uses flask. This flask application has several APIs, each API has a GET function that returns a json object.
I was asked to implement an additional API that requests information from the other APIs. So my question is how do I make a GET request directly to a flask application? Is it something like....
from flask import request
#app.route('/root_dir/api_number_1/info', methods=['GET'])
def request_info_from_api_number_1():
return request.get_json()
#app.route('/root_dir/api_number_2/info', methods=['GET'])
def request_info_from_api_number_2():
return request.get_json()
When I do this the functions return None. I suppose I could always make an http request to the flask url and specify the address as localhost but it seems strange to have to make an http request when I can directly access the flask app object.
Could you just use the existing api functions?
from flask import Flask
app = Flask(__name__)
#app.route("/foo")
def foo():
return "foo"
#app.route("/foobar")
def foobar():
return foo() + "bar"
if __name__ == "__main__":
app.run(debug=True)
I am learning how to use Pluggable Views in Flask, since it seems that everyone uses them always for their advantages. I have the following file which returns an "Not Implemented Error". I am assuming that is because I am not implementing the dispatch_request. However, according to Flask's documentation, when using MethodView: "...if you implement a method called get() it means you will response to ’GET’ requests and the dispatch_request() implementation will automatically forward your request to that." Meaning, I do not require dispatch_request.
from flask import Flask, render_template, request, redirect, url_for, flash
from flask.views import View, MethodView
import os
SECRET_KEY = 'some_secret_key'
DEBUG = TRUE
app = Flask(__name__)
app.config.from_object(__name__)
class Main(View):
def dispatch_request(self):
return "Hello World!"
class Template(View):
def get(self):
return render_template('index.html')
def post(self):
result = eval(request.form['expression'])
flash(result)
return self.get()
app.add_url_rule('/', view_func=Main.as_view('main'))
app.add_url_rule('/template', view_func=Template.as_view('template'), methods=['GET', 'POST'])
if __name__ == "__main__":
app.run()
Oops.. silly Python beginner's mistake by me.
I was subclassing flask.views.View instead of flask.views.MethodView. flask.views.View requires dispatch_request, and does not automatically forward HTTP requests to dispatch_request as MethdoView does, hence the error.