How can I override the static file handler in Flask? - python

Specifically, how can I assign a new handler to the "static" endpoint? I know I can change the static_folder and static_path, but I specifically want to assign a different function to handle requests of any url that are routed to the "static" endpoint in the routing map. I've tried assigning an empty werkzeug.routing.Map to the <Flask app>.url_map but to no avail - I still get an error ("View function mapping is overwriting an existing endpoint function: static") when attempting to add_url_rule.
Thanks in advance.

Set static_folder to None to prevent Flask from registering the view:
app = Flask(static_folder=None)
Now you are free to create your own.
Alternatively, have the static view use a different URL path, and give your alternative a different endpoint name:
app = Flask(static_url_path='/flask_static')
#route('/static/<path:filename>')
def my_static(filename):
# ...
Flask will always use the endpoint name static for the view it creates, so the above uses my_static instead.

Related

How to get the name of the Flask blueprint inside a template?

I have a site built with Flask. It has several sections, each with a dedicated blueprint. The templates in each blueprint extend a base template, which has the basic layout for each page, including a navigation bar with tabs for each section.
I'd like to have the base template highlight the current tab, so it needs to know which blueprint's view is handling the request.
One way I came up with to do this is to add a before_request handler to each blueprint and store the name in g:
bp = Blueprint('blog', __name__, url_prefix='/blog')
#bp.before_request
def set_bp_name():
g.section = 'blog'
But Flask must know which blueprint is handling a request (if any) and the blueprint, of course, knows its own name. Is there a way for the template to fetch the current blueprint's name that doesn't require modifying each blueprint?
Yes. Quite simply: request.blueprint.
The request object is one of a few (along with g) that Flask makes available to all templates. It contains the blueprint property, which is the name of the blueprint handling the current request.

Is there an alternative to url_for for CherryPy?

Flask has a url_for method call, to set up urls from its global settings folder.
How do I manage something similar to that with CherryPy?
Is this what you are looking for?
You can access the mounted url handlers through
cherrypy.tree.apps[mount_point].root
root is always the mounted instance to the mount point. So a reverse function would look like:
def reverse(cls):
# get link to a class type
for app_url in cherrypy.tree.apps.keys():
if isinstance(cherrypy.tree.apps[app_url].root, cls):
# NOTE: it will return with the first mount point of this class
return app_url
how to get url of an object in cherrypy?
Hope this helps!
If you use routes dispatcher, you have its url_for.

Custom routing in Flask app

I've been trying to understand how to generate dynamic Flask URLs. I've read the docs and several example, but can't figure out why this code doesn't work:
path = 'foo'
#app.route('/<path:path>', methods=['POST'])
def index(path=None):
# do some stuff...
return flask.render_template('index.html', path=path)
I'd expect my index.html template to be served to /foo, but it is not. I get a build error. What am I missing?
If I use a fixed path, like /bar, everything works without issue.
#app.route('/bar', methods=['POST'])
You've got the long and short of it already. All you need to do is decorate your view functions using the /<var> syntax (or the /<converter:var> syntax where appropriate).
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/<word>', defaults={'word': 'bird'})
def word_up(word):
return render_template('whatstheword.html', word=word)
#app.route('/files/<path:path>')
def serve_file(path):
return send_from_directory(app.config['UPLOAD_DIR'], path, as_attachment=True)
if __name__ == '__main__':
app.debug = True
app.run(port=9017)
When Flask pulls a variable out of a URL for a dynamic route like you're trying to use, it'll be a unicode string in Python by default. If you create the variable with the <int:var> or <float:var> converters, it'll be converted to the appropriate type in the app space for you.
The <path:blah> converter will match on a string that contains slashes (/), so you can pass /blah/dee/blah and the path variable in your view function will contain that string. Without using the path converter, flask would try and dispatch your request to a view function registered on the route /blah/dee/blah, because the plain <var> is delineated by the next / in the uri.
So looking at my little app, the /files/<path:path> route would serve whatever file it could find that matched the path sent up by the user on the request. I pulled this example from the docs here.
Also, dig that you can specify defaults for your variable URLs via a keyword arg to the route() decorator.
If you want, you can even access the underlying url_map that Werkzeug builds based on how you specify your view functions and routes in your app space. For more stuff to chew on, check out the api docs on URL registrations.
You can use add_url_rule():
def index(path=None):
return render_template('index.html', path=path)
path = '/foo'
app.add_url_rule(path, 'index', index)
You also might want to look at blueprint objects if you end up doing this alot.

What is an 'endpoint' in Flask?

The Flask documentation shows:
add_url_rule(*args, **kwargs)
Connects a URL rule. Works exactly like the route() decorator.
If a view_func is provided it will be registered with the endpoint.
endpoint – the endpoint for the registered URL rule. Flask itself assumes the name of the view function as endpoint
What exactly is meant by an "endpoint"?
How Flask Routing Works
The entire idea of Flask (and the underlying Werkzeug library) is to map URL paths to some logic that you will run (typically, the "view function"). Your basic view is defined like this:
#app.route('/greeting/<name>')
def give_greeting(name):
return 'Hello, {0}!'.format(name)
Note that the function you referred to (add_url_rule) achieves the same goal, just without using the decorator notation. Therefore, the following is the same:
# No "route" decorator here. We will add routing using a different method below.
def give_greeting(name):
return 'Hello, {0}!'.format(name)
app.add_url_rule('/greeting/<name>', 'give_greeting', give_greeting)
Let's say your website is located at 'www.example.org' and uses the above view. The user enters the following URL into their browser:
http://www.example.org/greeting/Mark
The job of Flask is to take this URL, figure out what the user wants to do, and pass it on to one of your many python functions for handling. It takes the path:
/greeting/Mark
...and matches it to the list of routes. In our case, we defined this path to go to the give_greeting function.
However, while this is the typical way that you might go about creating a view, it actually abstracts some extra info from you. Behind the scenes, Flask did not make the leap directly from URL to the view function that should handle this request. It does not simply say...
URL (http://www.example.org/greeting/Mark) should be handled by View Function (the function "give_greeting")
Actually, it there is another step, where it maps the URL to an endpoint:
URL (http://www.example.org/greeting/Mark) should be handled by Endpoint "give_greeting".
Requests to Endpoint "give_greeting" should be handled by View Function "give_greeting"
Basically, the "endpoint" is an identifier that is used in determining what logical unit of your code should handle the request. Normally, an endpoint is just the name of a view function. However, you can actually change the endpoint, as is done in the following example.
#app.route('/greeting/<name>', endpoint='say_hello')
def give_greeting(name):
return 'Hello, {0}!'.format(name)
Now, when Flask routes the request, the logic looks like this:
URL (http://www.example.org/greeting/Mark) should be handled by Endpoint "say_hello".
Endpoint "say_hello" should be handled by View Function "give_greeting"
How You Use the Endpoint
The endpoint is commonly used for the "reverse lookup". For example, in one view of your Flask application, you want to reference another view (perhaps when you are linking from one area of the site to another). Rather than hard-code the URL, you can use url_for(). Assume the following
#app.route('/')
def index():
print url_for('give_greeting', name='Mark') # This will print '/greeting/Mark'
#app.route('/greeting/<name>')
def give_greeting(name):
return 'Hello, {0}!'.format(name)
This is advantageous, as now we can change the URLs of our application without needing to change the line where we reference that resource.
Why not just always use the name of the view function?
One question that might come up is the following: "Why do we need this extra layer?" Why map a path to an endpoint, then an endpoint to a view function? Why not just skip that middle step?
The reason is because it is more powerful this way. For example, Flask Blueprints allow you to split your application into various parts. I might have all of my admin-side resources in a blueprint called "admin", and all of my user-level resources in an endpoint called "user".
Blueprints allow you to separate these into namespaces. For example...
main.py:
from flask import Flask, Blueprint
from admin import admin
from user import user
app = Flask(__name__)
app.register_blueprint(admin, url_prefix='admin')
app.register_blueprint(user, url_prefix='user')
admin.py:
admin = Blueprint('admin', __name__)
#admin.route('/greeting')
def greeting():
return 'Hello, administrative user!'
user.py:
user = Blueprint('user', __name__)
#user.route('/greeting')
def greeting():
return 'Hello, lowly normal user!'
Note that in both blueprints, the '/greeting' route is a function called "greeting". If I wanted to refer to the admin "greeting" function, I couldn't just say "greeting" because there is also a user "greeting" function. Endpoints allow for a sort of namespacing by having you specify the name of the blueprint as part of the endpoint. So, I could do the following...
print url_for('admin.greeting') # Prints '/admin/greeting'
print url_for('user.greeting') # Prints '/user/greeting'
Endpoint is the name used to reverse-lookup the url rules with url_for and it defaults to the name of the view function.
Small example:
from flask import Flask, url_for
app = Flask(__name__)
# We can use url_for('foo_view') for reverse-lookups in templates or view functions
#app.route('/foo')
def foo_view():
pass
# We now specify the custom endpoint named 'bufar'. url_for('bar_view') will fail!
#app.route('/bar', endpoint='bufar')
def bar_view():
pass
with app.test_request_context('/'):
print url_for('foo_view')
print url_for('bufar')
# url_for('bar_view') will raise werkzeug.routing.BuildError
print url_for('bar_view')
If you have same class name and want to map with multiple routes, then specify the endpoint, so that framework will differentiate between two:
class ClassName(Resource):
def get(self):
if request.endpoint!='hello':
return {"data": "Hello"}
elif:
return {"data" : "World"}
api.add_resource(ClassName, '/rout1', endpoint = "world")
api.add_resource(ClassName, '/rout2', endpoint="hello")
#app.route('/') #Endpoint
def a_function(): #View function
return 'view'
Inside Flask, every endpoint with its request methods mapped to a view function. When you use app.route decorator you are actually adding a URL rule.

How to create dynamic subdomains in a Flask application

I am trying to setup variable route handling in a Flask application such as described in this answer: Dynamic Subdomain Handling in a Web App (Flask)
However, I want to be able to recognize certain subdomains BEFORE they are caught by the variable route so I can use the flask-restful api extension (Routing with RESTful).
For example, I have tried the following:
#app.route('/', subdomain="<user>", defaults={'path':''})
#app.route('/<path:path>', subdomain="<user>")
def user_profile(user,path):
pass
class Api(restful.Resource):
def get(self):
#Do Api things.
api.add_resource(Api, '/v1', subdomain="api")
When I test this, all of URLs go to the variable route handler and call user_prof(). I tried putting the api route first and the standard #app.route rule second and vice versa but there was no change.
Am I missing some other parameter or need to go deeper in Flask to make this happen?
Update:
The URL patterns I am trying to match are like this:
user1.mysite.com -> handled by user_profile()
user2.mysite.com -> handled by user_profile()
any_future_string.mysite.com -> handled by user_profile()
api.mysite.com/v1 -> handled by Api class
Other cases include:
www.mysite.com -> handled by index_display()
mysite.com -> handled by index_display()
#app.before_request
def before_request():
if 'api' == request.host[:-len(app.config['SERVER_NAME'])].rstrip('.'):
redirect(url_for('api'))
#app.route('/', defaults={'path': ''}, subdomain='api')
#app.route('/<path:path>', subdomain='api')
def api(path):
return "hello"
This should work. Add your api version to the path if needed or that could be processed by your API class.
To keep it simple, I redesigned the logic of my application into two distinct parts.
This way the Flask application only handles the API endpoint logic. The user profile logic is handled by another application. I can now add multiple Resources to the API application without worry about breaking the routing.

Categories