customize the method not allow response in flask - python

in Flask Framework, define a route
#main.route('/')
def index():
return render_template('index.html')
only can you use get method to request the index.html.
if I try to post some data to the index.html.
I got a method not allow webpage return. and that's correct.
but my problem is, Is there anyway I can customize the page by myself?
for example, return json data, instead of a method not allowed webpage??

You can create error handler
from flask import jsonify
#app.errorhandler(405)
def method_not_allowed(e):
return jsonify({'error': 405}), 405
http://flask.pocoo.org/docs/0.10/patterns/errorpages/

Related

Make flask only accept POST requests on a route

I want to build a Flask route which only accepts POST requests.
So far, I have tried achieving this goal by usind the methods parameter of the route decorator.
#app.route("/register")
def register(methods=["POST"]):
return "register endpoint"
However, when trying to send a GET request to this route with Postman, it simply returns "register endpoint", even though i only added POST to the methods parameter.
How can I make my route ONLY accept POST requests and return an error in all other cases?
You almost got it, the "methods=[]" should be in the decorator :
#app.route("/register", methods=["POST"])

Is there a way to test if flask template contains a link?

I've been testing whether routes exist using
def test_index(self):
r = self.app.get("/")
self.assertEqual(200, r.status_code, "Status code was not 'OK'.")
My template has a hyperlink to another page. Is there a way to test if this exists?
Well, if you are testing templates, every template you render is the result of a request to some route. If you render url's in a template using url_for(), then it will raise a BuildError if the url is pointing to a non existing route, and the server will return the status code 500. Therefore, you don't need to parse your templates manually for testing purposes if you just check the route instead.
Example:
from flask import Flask, render_template_string
app = Flask(__name__)
#app.route('/index')
def index():
return render_template_string("""
{{ url_for('index') }}
{{ url_for('blabla') }}
""")
def test_index(self):
r = self.app.get("/index")
self.assertEqual(200, r.status_code, "Status code was not 'OK'.")
This will result in a
routing.BuildError: Could not build url for endpoint 'blabla'. Did you mean 'static' instead? error, which makes your tests fail.
I hope this explanation is clear enough!

Disable Flask warnings about view functions not returning a response?

I am developing an API using Flask, a service not meant to be rendering any templates but simply returning json in the form of {"message": "message here", "status_code": 200, "data": {}}".
I have several routes and each modifies a global response object attached to Flask.g:
from flask import g
from project import app
#app.route('/users/', methods=["GET"])
def get_users():
...
g.res.data["message"] = "Successfully queried users as specified."
# default g.res.status_code == 200
#app.route('/users/', methods=["POST"])
def post_users():
...
g.res.data["message"] = "Successfully created User."
g.res.status_code = 201
Then, returning the response data to the user is handled by an app.after_request:
from flask import g, jsonify
from project import app
#app.after_request
def after_request(response: None):
return jsonify(g.res)
However, Flask still (correctly) believes that the view function is not returning a response, since technically the view function is not, but the after_request handler is.
Is there any inherit problems in my approach to handling the response data? I purposely switched to using app.after_request to avoid duplicating return jsonify(g.res) at the end of each view function.
If there are no problems with this way, how should I go about disabling these warnings?
Edit: The error is being raised in Flask.app.make_response where a ValueError is raised on the response being None and other conversions are attempted later (from a str to a Flask.Response object, for example).
I will likely just modify this file directly to handle my specific use-case until I find an idiomatic way to approach this.
Subclass the Flask class and override the make_response method. Move the logic from your handler into the method. If there was no response returned by the view but there is valid data in g.res, then build the response and return it, otherwise defer to the default behavior.
class GResFlask(Flask):
def make_response(self, rv):
if not rv and g.res.data:
return jsonify(g.res)
return super().make_response(rv)
app = GResFlask(__name__)
It's important to note that after_request handlers may be added by extensions, and the interface provided by Flask means that they will be expecting a valid response object. So you always want to return a valid response from make_response.

How do I perform a common function before requesting *any* web page?

Lets say that I have the following
from flask import Flask, render_template
import config
import utils
app = Flask(__name__)
#app.route("/")
def index():
# call utils.function_foo(app)
return render_template("index.html")
#app.route("/about/")
def about():
# call utils.function_foo(app)
return render_template("about.html")
# ... more endpoint handling
if __name__ == "__main__":
app.run(debug=True)
What I want to do is perform function_foo before each routing function has a chance to return.
#app.before_request
def function_foo(app):
# Something foo'ey.
Is not the solution since this calls function_foo every time the server gets any HTTP request.
This means that if I request the about page, and it has 30 images, js files, css files, etc that it has to request, then function_foo will be called 31 times before the about page is loaded. I want function_foo to be called once in this case, not 31.
If anyone knows a thing about this, then I would greatly appreciate some information on it.
Cheers!
If you want to call a function before or after the route function, you can write your own decorator.
It seams that you don't really want that:
What I want to do is perform function_foo before each routing function has a chance to return.
If you want to call function_foo before the rendering, you can write your own rendering function:
def my_rendering(*args, **kwargs):
function_foo()
return render_template(*args, **kwargs)

Redirecting to an external domain in Flask

I'm writing a very simple flask app (a URL shortener) that should be able to redirect certain requests to other arbitrary domains. However, I am running into problems with the redirection. This stripped-down version, for example, doesn't work:
from app import app, db
from flask import abort, redirect
#app.route('/')
def index():
return "Hello, world"
#app.route('/favicon.ico')
def favicon():
abort(404)
#app.route('/<slug>')
def redirect(slug):
return redirect('http://google.com/')
Perhaps naively, I expected this to redirect to google.com, but instead the redirect seems to get "captured" by Flask, and it tries to route the redirected URL back through the redirect handler (e.g. redirect(slug="http://google.com/")) until it eats all the stack space through recursion and errors out. I can't seem to figure out why this would happen, or how to work around it, but I'd really appreciate a pointer in the right direction.
The problem is in this function:
#app.route('/<slug>')
def redirect(slug):
return redirect('http://google.com/')
You named the function redirect(), so in the scope of the function when you call return redirect(...) this is interpreted as a recursive call because the view function shadows Flask's function of the same name. And the URL that you pass is mapped to the slug argument in the recursive call.
Change the name of the view function from redirect() to something else and your code will work just fine.

Categories

Resources