How to change routes in Flask? - python

I have watched a tutorial on Flask and I can't seem to understand how does this code work
def my_home():
return render_template("./index.html")
#app.route('/<string:page_name>')
def html_page(page_name):
return render_template(page_name)```
Specifically /<string:page_name> is confusing to me, how does it understand what is page_name and redirect to that page?
Thank you!

The answer to this is in the magic of decorators and not flask itself. A decorator is a high level function which accepts a function and manipulates it accordingly. See the following example:
def route(func, user_path):
# internal flask mechanisms here
def callback(user_path):
return http.route(user_path, func)
return callback
#route("hello_world")
def render():
return "Hello World"
The decorator is taking your function as an input and performing some actions to correlate the path with your given input. This can obviously be used for many other purposes. For example, flask also allows an additional decorator to define the type of request allowed for the function, such as GET, POST, etc.
To answer your question, flask is accepting a URL parameter and generating the page based on that given parameter. This is known as dynamic routing and is used for database query purposes based on the route (though the given example is trivial). So if someone goes to page_name "John", you can use that value and template it in your html to dynamically say hi to John (and whomever else).

/<string:page_name>
means that Flask expects a customised string after your domain i.e.
www.yourdomain.com/anycustomisedstring
/<data_type:your_variable_name> i.e. /<integer:page_number>
in this case, your variable is passed as a parameter to your function. This function returns the site that is passed in the URL as a string

Related

Trying to pass an argument to a function, can get through the ''#app.route'' in python flask

I am trying to pass an argument to a function I made into app.route.
In the following code, I create 2 pages, 1 Homepage and 1 Admin page.
I want to permit or deny access to the /admin page depending if I have the parameter ADMINpass set to False or True in my python code directly.
I understand that in this particular situation, it will work, as I don't need to pass the argument, but if I define my admin page in another subscript and import it in mainscript, it will tell me that ''admin takes exactly 1 argument (0 given). So I want this function to work for whatever case.
I don't really worry about security for now as I am testing things.
Thanks alot and apologies if a similar question has already been posted. Here is the code:
###User section, importing parameters
ADMINpass=False
###End of user section
##Main code
#app.route('/') #Home page
def homepage():
return 'Hello, main page here'
#app.route('/admin') #Admin page that I want to access
def admin(ADMINpass): #Trying to pass the argument here will not work, probably because of the app.route
if ADMINpass==False: #If admin not activated in code, redirect to homepage
a=redirect(url_for('homepage'))
if ADMINpass == True: #If admin is activated, permit access
print('This is the admin page')
if __name__== '__main__':
app.run()
There are several issues here.
The #app.route decorator is a wrapper around the admin() function. It provides the extra functionality that does route registration (the thing that allows the '/admin' string to be an endpoint), request handling (you could specify HTTP methods like 'POST' with it), and more (see Flask docs for route()).
So if you did this:
#app.route('/admin') #Admin page that I want to access
def admin(ADMINpass): #Trying to pass the argument here will not work, probably because of the app.route
Flask expects you to use this for parameterising the endpoint itself:
#app.route('/endpoint/<something>')
def func(something):
return something
$ curl localhost:5000/endpoint/value_of_something
value_of_something
I would suggest Miguel Grinberg's guide to decorators for more info on decorators with a focus on Flask.
Coming back to your issue, you could do this (but read on to see why I think you shouldn't):
ADMINpass=False
#app.route('/endpoint')
def admin():
global ADMINpass
return f'ADMINpass is {ADMINpass}'
The problem with global variables is that they could be changed at any point in some other piece of code. This is generally a good way to introduce mistakes in your code and make your code less maintainable and more difficult to test.
With servers, the problem is more fundamental - what if your code grew to look something like this?
ADMINpass=False
#app.route('/endpoint')
def admin():
global ADMINpass
ADMINpass = not ADMINpass
return f'ADMINpass is {ADMINpass}'
Every request (which may be coming from different clients) would change it, so its value is nearly impossible to reason about:
$ curl localhost:5000/endpoint
ADMINpass is False
$ curl localhost:5000/endpoint
ADMINpass is True
$ curl localhost:5000/endpoint
ADMINpass is False
You might be looking for Flask session objects. The values stored in the session object are specific to each client because its implementation is based on cookies. If it's an authentication mechanism implementation you're going towards, this may be exactly what you need.
from flask import session
app.something = 'value_of_something_else'
#app.route('/endpoint')
def admin():
return app.something
$ curl localhost:5000/endpoint
value_of_something_else
If a single static value is what you need, one way to overcome the errors you're likely getting when trying to use the variable would be to use a function you can always call:
def admin_pass():
return False
#app.route('/endpoint')
def admin():
if not admin_pass():
...

Flask trying to call function with a redirect

I’m using Flask with pluggable views. Having some trouble getting a redirect to work. Here is the code.
def some_redirect():
*condition for redirect*
return redirect(url)
class SomeClass(View):
*few methods*
def dispatch_request(self):
some_redirect()
*other stuff*
Essentially all I want to do is check is either a certain value in session exists or if a certain config key is present. If not, I’d like to redirect to an external url. Using some print statements I can see that the code reaches the redirect. But instead of sending me to someurl.com, it continues in dispatch request. I don’t want to use a decorator here because I’m not really modifying any of these methods. I essentially just want to redirect to the given url if those conditions are not met. Any help would be much appreciated.
You need to return the result of the function:
def dispatch_request(self):
redirect = redirect_if_unauthorized()
if redirect:
return redirect

Efficient way of handling XHR request in Python Flask

Currently I am using following way of views to determine if request is AJAX / XHR. Accordingly I am returning json data and rendering the template file in Flask. This working perfectly so for in my application.
from flask import request, render_template, jsonify
#cinemascope.route('/cinema')
def cinema():
if request.is_xhr:
cinema = Cinema.query.all()
return jsonify({'cinema_scope': cinema})
return render_template('cinema.html')
But I see this way little problematic as my application might many more #app.routes and every time I will have to repeat the code (if clause) so its loosing upon the maintainability aspect.
I am thinking about the two options here -
Option # 1 - Writing a simple function to wrap the if clause from above route.
Option # 2 - writing a decorator which will determine the request and accordingly it can be called from route - in a way decorator will handle the redundant part of code. I dont know too much about writing custom decorators so far though after reading little about it seems to be the best option.
Any further direction in adopting any of above approaches will be appreciated.
Basically I want to know the way - so I can avoid if clause part of code in each and every #app.route.
I refered - from http://justindonato.com/notebook/template-or-json-decorator-for-flask.html
This is what my decorator looks like
from functools import wraps
def xhr_request_check(template=None):
def decorator_request_parser(f):
#wraps(f)
def decorator_request(*args, **kwargs):
func_data = f(*args, **kwargs)
if request.is_xhr or not template:
return jsonify(func_data)
else:
return render_template(template, **func_data)
return decorator_request
return decorator_request_parser
In my view I have written
from flask import request, render_template, jsonify
#catalog.route('/cinema')
#xhr_request_check('cinema.html')
def cinema():
cinema = Cinema.query.all()
return {'cinema_scope': cinema}
Now I just needs to add #xhr_request_check('cinema.html') to each route and it is working perfectly.
Please let me know if any one would even better solution from code optimization perspective.
The way of doing this would be to create a decorator, which are essentially functions which take a function as an input and return a function as an output. They are not specific to flask, but python in general.
Here is an example for flask:
How to make a python decorator function in Flask with arguments (for authorization)
is_xhr is deprecated, but you could check on the Accepts header instead.

Flask: How do I get the returned value from a function that uses #app.route decorator?

So I'm pretty new to Flask and I'm trying to make my mind around one thing. So, if I understand well when you write a function within a Flask app and you use the #app.route decorator in that function, it only runs when you hit that path/url.
I have a small oauth app written in Flask that goes through all the authorization flow and then it return the token.
My question is how do I get that token from the #decorated function? For example, lets say I have something like this:
#app.route(/token/)
def getToken(code): #code from the callback url.
#/Stuff to get the Token/
#/**********************/
return token
If I hit the (/token/) url-path the function returns the token. But now I need to get that token and use it in another function to write and read from the API I just got the token from. My initial thought was doing this:
token = getToken(code)
But if I do that, I get this error:
RuntimeError: working outside of request context
So again, my question is, how do I get the token so I can pass it as a parameter to other functions.
Extract the token generation code into a separate function, so that you can call it from anywhere, including the view function. It's a good practice to keep the application logic away from the view, and it also helps with unit testing.
I assume your route includes a placeholder for code, which you skipped:
def generateToken(code):
#/Stuff to get the Token/
#/**********************/
return token
#app.route('/token/<string:code>')
def getToken(code):
return generateToken(code)
Just keep in mind that generateToken shouldn't depend on the request object. If you need any request data (e.g. HTTP header), you should pass it explicitly in arguments. Otherwise you will get the "working outside of request context" exception you mentioned.
It is possible to call request-dependent views directly, but you need to mock the request object, which is a bit tricky. Read the request context documentation to learn more.
not sure what the context is. You could just call the method.
from yourmodule import get_token
def yourmethod():
token = get_token()
Otherwise, you could use the requests library in order to retrieve the data from the route
>>> import requests
>>> response = requests.get('www.yoursite.com/yourroute/')
>>> print response.text
If you're looking for unittests, Flask comes with a mock client
def test_get_token():
resp = self.app.get('/yourroute')
# do something with resp.data

Cherrypy index dispatcher not like defined

This is my first outing with CherryPy so forgive any stupidity.
I'm trying to write a RESTful API that in part deals with adding/removing people. I want to be able to GET/PUT/DELETE example.com/people/.
The dispatcher seems to be behaving totally differently for the index method vs a defined function:
class people:
"""This is the class for CherryPy that deals with CRUD on people"""
#cherrypy.expose
def index(self, name):
return name
#cherrypy.expose
def who(self, name):
return name
root = webroot()
root.people = people()
cherrypy.quickstart(root)
If I call example.com/people/tom, I get a 404, if I call example.com/people/who/tom I get 'tom' returned.
Can anyone see what I'm doing wrong? Is there a way I can pass /xxx to index?
Indexes are a bit different when it comes to URL arguments.
The index method has a special role in CherryPy: it handles intermediate URI’s that end in a slash; for example, the URI /orders/items/ might map to root.orders.items.index. The index method can take additional keyword arguments if the request includes querystring or POST params; see Keyword Arguments, next. However, unlike all other page handlers, it cannot take positional arguments
source
However, the url of example.com/people?name=tom should work as you expect.

Categories