Add prefix for all Flask routes

I have a prefix that I want to add to each route. Right now I am adding a constant to the route with every definition. Is there any way to do this automatically?

PREFIX = "/abc/123" @app.route(PREFIX + "/") def index_page(): return "This is a website about burritos" @app.route(PREFIX + "/about") def about_page(): return "This is a website about burritos" 
+71
python flask routes
Sep 23 '13 at 19:39 on
source share
10 answers

The answer depends on how you maintain this application.

Sub-installed inside another WSGI container

Assuming you are going to run this application inside a WSGI container (mod_wsgi, uwsgi, gunicorn, etc.); you need to actually mount the application in this prefix as part of this WSGI container (anything that says WSGI) and set APPLICATION_ROOT for your prefix:

 app.config["APPLICATION_ROOT"] = "/abc/123" @app.route("/") def index(): return "The URL for this page is {}".format(url_for("index")) # Will return "The URL for this page is /abc/123/" 

Setting the APPLICATION_ROOT configuration value simply restricts the flash drive cookie for this URL prefix. Everything else will be automatically processed for you by Flask and Werkzeug with superior WSGI processing capabilities.

An example of the correct tuning of your application

If you donโ€™t know what the first paragraph means, look at this sample application with a USB flash drive installed inside it:

 from flask import Flask, url_for from werkzeug.serving import run_simple from werkzeug.wsgi import DispatcherMiddleware app = Flask(__name__) app.config['APPLICATION_ROOT'] = '/abc/123' @app.route('/') def index(): return 'The URL for this page is {}'.format(url_for('index')) def simple(env, resp): resp(b'200 OK', [(b'Content-Type', b'text/plain')]) return [b'Hello WSGI World'] app.wsgi_app = DispatcherMiddleware(simple, {'/abc/123': app.wsgi_app}) if __name__ == '__main__': app.run('localhost', 5000) 

Proxying Application Requests

If, on the other hand, you start the Flask application in the WSGI root container and request its proxy (for example, if it is FastCGI'd or nginx proxy_pass -ing requests for a sub-endpoint to your standalone uwsgi / gevent , then you can:

  • Use Blueprint, as Miguel points out in his answer .
  • or use DispatcherMiddleware from werkzeug (or PrefixMiddleware from su27 answer ) to connect your application to the stand-alone WSGI server you are using. (See an example of the correct tuning of your application above for the code used).
+59
Sep 23 '13 at 19:57
source share

You can put your routes on the plan:

 bp = Blueprint('burritos', __name__, template_folder='templates') @bp.route("/") def index_page(): return "This is a website about burritos" @bp.route("/about") def about_page(): return "This is a website about burritos" 

Then you register the project with the application using the prefix:

 app = Flask(__name__) app.register_blueprint(bp, url_prefix='/abc/123') 
+73
Sep 23 '13 at 21:24
source share

It should be noted that APPLICATION_ROOT NOT for this purpose.

All you have to do is write middleware to make the following changes:

  • change PATH_INFO to handle the URL prefix.
  • edit SCRIPT_NAME to create a prefix URL.

Like this:

 class PrefixMiddleware(object): def __init__(self, app, prefix=''): self.app = app self.prefix = prefix def __call__(self, environ, start_response): if environ['PATH_INFO'].startswith(self.prefix): environ['PATH_INFO'] = environ['PATH_INFO'][len(self.prefix):] environ['SCRIPT_NAME'] = self.prefix return self.app(environ, start_response) else: start_response('404', [('Content-Type', 'text/plain')]) return ["This url does not belong to the app.".encode()] start_response): class PrefixMiddleware(object): def __init__(self, app, prefix=''): self.app = app self.prefix = prefix def __call__(self, environ, start_response): if environ['PATH_INFO'].startswith(self.prefix): environ['PATH_INFO'] = environ['PATH_INFO'][len(self.prefix):] environ['SCRIPT_NAME'] = self.prefix return self.app(environ, start_response) else: start_response('404', [('Content-Type', 'text/plain')]) return ["This url does not belong to the app.".encode()] 

Wrap the application with middleware, for example:

 from flask import Flask, url_for app = Flask(__name__) app.debug = True app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix='/foo') @app.route('/bar') def bar(): return "The URL for this page is {}".format(url_for('bar')) if __name__ == '__main__': app.run('0.0.0.0', 9010) 

Visit http://localhost:9010/foo/bar ,

You will get the correct result: The URL for this page is /foo/bar

And don't forget to set a cookie domain if you need to.

This solution is given by Larivact gist . APPLICATION_ROOT not for this job, although it seems like it is. This is really confusing.

+31
Mar 16 '16 at 10:57
source share

This is more a python answer than a Flask / werkzeug answer; but it just works.

If, like me, you want your application settings (loaded from the .ini file) to also contain your Flask application prefix (so as not to set a value during deployment, but at runtime), you can choose the following:

 def prefix_route(route_function, prefix='', mask='{0}{1}'): ''' Defines a new route function with a prefix. The mask argument is a `format string` formatted with, in that order: prefix, route ''' def newroute(route, *args, **kwargs): '''New function to prefix the route''' return route_function(mask.format(prefix, route), *args, **kwargs) return newroute 

Perhaps this is somewhat hacky and relies on the fact that the route function of the bulb requires route as the first positional argument.

You can use it as follows:

 app = Flask(__name__) app.route = prefix_route(app.route, '/your_prefix') 

NB: it costs nothing to use a variable in the prefix (for example, setting it to /<prefix> ), and then process this prefix in the functions that you decorate with @app.route(...) . If you do this, you obviously need to declare a prefix parameter in your decorated functions. In addition, you can check the presented prefix for some rules and return 404 if the check failed. To avoid 404 custom reimplementations, please from werkzeug.exceptions import NotFound , and then raise NotFound() if the verification fails.

+8
Jun 17 '16 at 9:51 on
source share

So, I believe that the correct answer to this question is: the prefix should be configured in the actual server application that you use when development is complete. Apache, nginx, etc.

However, if you want this to work during development when starting the Flask application in debugging, check out this method .

Flask DispatcherMiddleware to the rescue!

I will copy the code here for posterity:

 "Serve a Flask app on a sub-url during localhost development." from flask import Flask APPLICATION_ROOT = '/spam' app = Flask(__name__) app.config.from_object(__name__) # I think this adds APPLICATION_ROOT # to the config - I'm not exactly sure how! # alternatively: # app.config['APPLICATION_ROOT'] = APPLICATION_ROOT @app.route('/') def index(): return 'Hello, world!' if __name__ == '__main__': # Relevant documents: # http://werkzeug.pocoo.org/docs/middlewares/ # http://flask.pocoo.org/docs/patterns/appdispatch/ from werkzeug.serving import run_simple from werkzeug.wsgi import DispatcherMiddleware app.config['DEBUG'] = True # Load a dummy app at the root URL to give 404 errors. # Serve app at APPLICATION_ROOT for localhost development. application = DispatcherMiddleware(Flask('dummy_app'), { app.config['APPLICATION_ROOT']: app, }) run_simple('localhost', 5000, application, use_reloader=True) 

Now, when you run the above code as a stand-alone Flask application, http://localhost:5000/spam/ display Hello, world! .

In a comment on another answer, I said that I wanted to do something like this:

 from flask import Flask, Blueprint # Let pretend module_blueprint defines a route, '/record/<id>/' from some_submodule.flask import module_blueprint app = Flask(__name__) app.config['APPLICATION_ROOT'] = '/api' app.register_blueprint(module_blueprint, url_prefix='/some_submodule') app.run() # I now would like to be able to get to my route via this url: # http://host:8080/api/some_submodule/record/1/ 

Applying DispatcherMiddleware to my far-fetched example:

 from flask import Flask, Blueprint from flask.serving import run_simple from flask.wsgi import DispatcherMiddleware # Let pretend module_blueprint defines a route, '/record/<id>/' from some_submodule.flask import module_blueprint app = Flask(__name__) app.config['APPLICATION_ROOT'] = '/api' app.register_blueprint(module_blueprint, url_prefix='/some_submodule') application = DispatcherMiddleware(Flask('dummy_app'), { app.config['APPLICATION_ROOT']: app }) run_simple('localhost', 5000, application, use_reloader=True) # Now, this url works! # http://host:8080/api/some_submodule/record/1/ 
+3
May 18 '16 at 19:52
source share

Another completely different way is mountpoints in uwsgi .

From a document Hosting multiple applications in one process ( permalink ).

In uwsgi.ini you add

 [uwsgi] mount = /foo=main.py manage-script-name = true # also stuff which is not relevant for this, but included for completeness sake: module = main callable = app socket = /tmp/uwsgi.sock 

If you do not call your main.py file, you need to change both mount and module

Your main.py might look like this:

 from flask import Flask, url_for app = Flask(__name__) @app.route('/bar') def bar(): return "The URL for this page is {}".format(url_for('bar')) # end def 

And the nginx configuration (again for completeness):

 server { listen 80; server_name example.com location /foo { include uwsgi_params; uwsgi_pass unix:///temp/uwsgi.sock; } } 

Now calling example.com/foo/bar display /foo/bar as returned by the url_for('bar') flag, as it automatically adapts. Thus, your links will work without problems with prefixes.

+2
Nov 07 '17 at 10:13
source share

I needed a similar so-called "context root". I did this in the conf file under /etc/httpd/conf.d/ using WSGIScriptAlias:

myapp.conf:

 <VirtualHost *:80> WSGIScriptAlias /myapp /home/<myid>/myapp/wsgi.py <Directory /home/<myid>/myapp> Order deny,allow Allow from all </Directory> </VirtualHost> 

So now I can access my application as: http: // localhost: 5000 / myapp

See guide - http://modwsgi.readthedocs.io/en/develop/user-guides/quick-configuration-guide.html

+1
Aug 11 '17 at 18:14
source share

I always prefer to use the following when it comes to adding a prefix to the entire app :

 app = Flask(__name__, root_path='/operators') 

Clean and clear.

+1
Sep 07 '18 at 10:39
source share

My solution where flash and PHP applications coexist with nginx and PHP5.6

SAVE Flask in root and PHP in subdirectories

sudo vi / etc / php / 5.6 / fpm / php.ini Add 1 line cgi.fix_pathinfo = 0

sudo vi / etc / php / 5.6 / fpm / pool.d / www.conf listen = / run / php / php5.6-fpm.sock

uwsgi

sudo vi / etc / nginx / sites-available / default USE NESTED LOCATIONS for PHP and leave FLASK in the root

 server { listen 80 default_server; listen [::]:80 default_server; # SSL configuration # # listen 443 ssl default_server; # listen [::]:443 ssl default_server; # # Note: You should disable gzip for SSL traffic. # See: https://bugs.debian.org/773332 # # Read up on ssl_ciphers to ensure a secure configuration. # See: https://bugs.debian.org/765782 # # Self signed certs generated by the ssl-cert package # Don't use them in a production server! # # include snippets/snakeoil.conf; root /var/www/html; # Add index.php to the list if you are using PHP index index.html index.htm index.php index.nginx-debian.html; server_name _; # Serve a static file (ex. favico) outside static dir. location = /favico.ico { root /var/www/html/favico.ico; } # Proxying connections to application servers location / { include uwsgi_params; uwsgi_pass 127.0.0.1:5000; } location /pcdp { location ~* \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php/php5.6-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } location /phpmyadmin { location ~* \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php/php5.6-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # include snippets/fastcgi-php.conf; # # # With php7.0-cgi alone: # fastcgi_pass 127.0.0.1:9000; # # With php7.0-fpm: # fastcgi_pass unix:/run/php/php7.0-fpm.sock; #} # deny access to .htaccess files, if Apache document root # concurs with nginx one # #location ~ /\.ht { # deny all; #} } 

READ carefully https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms

We need to understand the location match (no): if there are no modifiers, the location is interpreted as a prefix match. This means that the specified location will be mapped to the beginning of the request URI to determine compliance. =: If an equal sign is used, this block will be considered matching if the request URI exactly matches the specified location. ~: If a tilde modifier is present, this location will be interpreted as a case-sensitive regex match. ~ *: If a tilde and asterisk modifier is used, the location block will be interpreted as a case-insensitive regular expression match. ^ ~: If the โ€œCarat and Tildaโ€ modifier is present, and if this block is selected as the best match for an irregular expression, matching with the regular expression will not take place.

Ordering is important, from the nginx "location" description:

To find the location that matches the given query, nginx first checks the locations specified using prefix strings (prefix locations). Among them, the location with the longest matching prefix is โ€‹โ€‹selected and remembered. Then regular expressions are checked in the order they appear in the configuration file. The regular expression search ends at the first match and the appropriate configuration is used. If no match with the regular expression is found, then the configuration of the location of the prefix previously remembered is used.

It means:

First = (matching "longest matching prefix"). Then implicit. (match "the longest matching prefix") Then the regular expression. (The first match)

+1
Nov 08 '18 at 6:31
source share
 from flask import Flask app = Flask(__name__) app.register_blueprint(bp, url_prefix='/abc/123') if __name__ == "__main__": app.run(debug='True', port=4444) bp = Blueprint('burritos', __name__, template_folder='templates') @bp.route('/') def test(): return "success" 
0
Jan 10 '19 at 11:30
source share



All Articles