URL Routing
When it comes to combining multiple controller or view functions (howeveryou want to call them), you need a dispatcher. A simple way would beapplying regular expression tests on PATH_INFO
and call registeredcallback functions that return the value.
Werkzeug provides a much more powerful system, similar to Routes. All theobjects mentioned on this page must be imported from werkzeug.routing
, notfrom werkzeug
!
Quickstart
Here is a simple example which could be the URL definition for a blog:
- from werkzeug.routing import Map, Rule, NotFound, RequestRedirect
- url_map = Map([
- Rule('/', endpoint='blog/index'),
- Rule('/<int:year>/', endpoint='blog/archive'),
- Rule('/<int:year>/<int:month>/', endpoint='blog/archive'),
- Rule('/<int:year>/<int:month>/<int:day>/', endpoint='blog/archive'),
- Rule('/<int:year>/<int:month>/<int:day>/<slug>',
- endpoint='blog/show_post'),
- Rule('/about', endpoint='blog/about_me'),
- Rule('/feeds/', endpoint='blog/feeds'),
- Rule('/feeds/<feed_name>.rss', endpoint='blog/show_feed')
- ])
- def application(environ, start_response):
- urls = url_map.bind_to_environ(environ)
- try:
- endpoint, args = urls.match()
- except HTTPException, e:
- return e(environ, start_response)
- start_response('200 OK', [('Content-Type', 'text/plain')])
- return ['Rule points to %r with arguments %r' % (endpoint, args)]
So what does that do? First of all we create a new Map
which storesa bunch of URL rules. Then we pass it a list of Rule
objects.
Each Rule
object is instantiated with a string that represents a ruleand an endpoint which will be the alias for what view the rule represents.Multiple rules can have the same endpoint, but should have different argumentsto allow URL construction.
The format for the URL rules is straightforward, but explained in detail below.
Inside the WSGI application we bind the url_map to the current request which willreturn a new MapAdapter
. This url_map adapter can then be used to matchor build domains for the current request.
The MapAdapter.match()
method can then either return a tuple in the form(endpoint, args)
or raise one of the three exceptionsNotFound
, MethodNotAllowed
,or RequestRedirect
. For more details about thoseexceptions have a look at the documentation of the MapAdapter.match()
method.
Rule Format
Rule strings basically are just normal URL paths with placeholders in theformat <converter(arguments):name>
, where converter and the argumentsare optional. If no converter is defined, the default converter is used(which means string in the normal configuration).
URL rules that end with a slash are branch URLs, others are leaves. If youhave strict_slashes enabled (which is the default), all branch URLs that arevisited without a trailing slash will trigger a redirect to the same URL withthat slash appended.
The list of converters can be extended, the default converters are explainedbelow.
Builtin Converters
Here a list of converters that come with Werkzeug:
- class
werkzeug.routing.
UnicodeConverter
(map, minlength=1, maxlength=None, length=None) - This converter is the default converter and accepts any string butonly one path segment. Thus the string can not include a slash.
This is the default validator.
Example:
- Rule('/pages/<page>'),
- Rule('/<string(length=2):lang_code>')
Parameters:
- map – the
Map
. - minlength – the minimum length of the string. Must be greateror equal 1.
- maxlength – the maximum length of the string.
- length – the exact length of the string.
- class
werkzeug.routing.
PathConverter
(map) - Like the default
UnicodeConverter
, but it also matchesslashes. This is useful for wikis and similar applications:
- Rule('/<path:wikipage>')
- Rule('/<path:wikipage>/edit')
Parameters:map – the Map
.
- class
werkzeug.routing.
AnyConverter
(map, *items) - Matches one of the items provided. Items can either be Pythonidentifiers or strings:
- Rule('/<any(about, help, imprint, class, "foo,bar"):page_name>')
Parameters:
- map – the
Map
. - items – this function accepts the possible items as positionalarguments.
- class
werkzeug.routing.
IntegerConverter
(map, fixed_digits=0, min=None, max=None, signed=False) - This converter only accepts integer values:
- Rule("/page/<int:page>")
By default it only accepts unsigned, positive values. The signed
parameter will enable signed, negative values.
- Rule("/page/<int(signed=True):page>")
Parameters:
- map – The
Map
. - fixed_digits – The number of fixed digits in the URL. If youset this to
4
for example, the rule will only match if theURL looks like/0001/
. The default is variable length. - min – The minimal value.
- max – The maximal value.
- signed – Allow signed (negative) values.
New in version 0.15: The signed
parameter.
- class
werkzeug.routing.
FloatConverter
(map, min=None, max=None, signed=False) - This converter only accepts floating point values:
- Rule("/probability/<float:probability>")
By default it only accepts unsigned, positive values. The signed
parameter will enable signed, negative values.
- Rule("/offset/<float(signed=True):offset>")
Parameters:
- map – The
Map
. - min – The minimal value.
- max – The maximal value.
- signed – Allow signed (negative) values.
New in version 0.15: The signed
parameter.
- Rule('/object/<uuid:identifier>')
New in version 0.10.
Parameters:map – the Map
.
Maps, Rules and Adapters
- class
werkzeug.routing.
Map
(rules=None, default_subdomain='', charset='utf-8', strict_slashes=True, redirect_defaults=True, converters=None, sort_parameters=False, sort_key=None, encoding_errors='replace', host_matching=False) - The map class stores all the URL rules and some configurationparameters. Some of the configuration values are only stored on theMap instance since those affect all rules, others are just defaultsand can be overridden for each rule. Note that you have to specify allarguments besides the rules as keyword arguments!
Parameters:
- rules – sequence of url rules for this map.
- default_subdomain – The default subdomain for rules without asubdomain defined.
- charset – charset of the url. defaults to
"utf-8"
- strict_slashes – Take care of trailing slashes.
- redirect_defaults – This will redirect to the default rule if itwasn’t visited that way. This helps creatingunique URLs.
- converters – A dict of converters that adds additional convertersto the list of converters. If you redefine oneconverter this will override the original one.
- sort_parameters – If set to True the url parameters are sorted.See url_encode for more details.
- sort_key – The sort key function for url_encode.
- encoding_errors – the error method to use for decoding
- host_matching – if set to True it enables the host matchingfeature and disables the subdomain one. Ifenabled the host parameter to rules is usedinstead of the subdomain one.
New in version 0.5: sort_parameters and sort_key was added.
New in version 0.7: encoding_errors and host_matching was added.
converters
The dictionary of converters. This can be modified after the classwas created, but will only affect rules added after themodification. If the rules are defined with the list passed to theclass, the converters parameter to the constructor has to be usedinstead.
- Add a new rule or factory to the map and bind it. Requires that therule is not bound to another map.
Parameters:rulefactory – a Rule
or RuleFactory
bind
(server_name, script_name=None, subdomain=None, url_scheme='http', default_method='GET', path_info=None, query_args=None)- Return a new
MapAdapter
with the details specified to thecall. Note that script_name will default to'/'
if not furtherspecified or None. The server_name at least is a requirementbecause the HTTP RFC requires absolute URLs for redirects and so allredirect exceptions raised by Werkzeug will contain the full canonicalURL.
If no path_info is passed to match()
it will use the default pathinfo passed to bind. While this doesn’t really make sense formanual bind calls, it’s useful if you bind a map to a WSGIenvironment which already contains the path info.
subdomain will default to the default_subdomain for this map ifno defined. If there is no default_subdomain you cannot use thesubdomain feature.
New in version 0.7: query_args added
New in version 0.8: query_args can now also be a string.
Changed in version 0.15: path_info
defaults to '/'
if None
.
bindto_environ
(_environ, server_name=None, subdomain=None)- Like
bind()
but you can pass it an WSGI environment and itwill fetch the information from that dictionary. Note that because oflimitations in the protocol there is no way to get the currentsubdomain and real server_name from the environment. If you don’tprovide it, Werkzeug will use SERVER_NAME and SERVER_PORT (orHTTP_HOST if provided) as used server_name with disabled subdomainfeature.
If subdomain is None but an environment and a server name isprovided it will calculate the current subdomain automatically.Example: server_name is 'example.com'
and the SERVER_NAME_in the wsgi _environ is 'staging.dev.example.com'
the calculatedsubdomain will be 'staging.dev'
.
If the object passed as environ has an environ attribute, the value ofthis attribute is used instead. This allows you to pass requestobjects. Additionally PATH_INFO added as a default of theMapAdapter
so that you don’t have to pass the path info tothe match method.
Changed in version 0.5: previously this method accepted a bogus _calculate_subdomain_parameter that did not have any effect. It was removed becauseof that.
Changed in version 0.8: This will no longer raise a ValueError when an unexpected servername was passed.
Parameters:
- **environ** – a WSGI environment.
- **server_name** – an optional server name hint (see above).
- **subdomain** – optionally the current subdomain (see above).
defaultconverters
= {'any':, 'default': , 'float': , 'int': , 'path': , 'string': , 'uuid': }_ A dict of default converters to be used.
- Iterate over all rules and check if the endpoint expectsthe arguments provided. This is for example useful if you havesome URLs that expect a language code and others that do not andyou want to wrap the builder a bit so that the current languagecode is automatically added if not provided but endpoints expectit.
Parameters:
- **endpoint** – the endpoint to check.
- **arguments** – this function accepts one or more argumentsas positional arguments. Each one of them ischecked.
Parameters:endpoint – if provided only the rules for that endpointare returned.Returns:an iterator
update
()- Called before matching and building to keep the compiled rulesin the correct order after things changed.
- class
werkzeug.routing.
MapAdapter
(map, server_name, script_name, subdomain, url_scheme, path_info, default_method, query_args=None) Returned by
Map.bind()
orMap.bind_to_environ()
and doesthe URL matching and building based on runtime information.
New in version 0.7.
build
(endpoint, values=None, method=None, force_external=False, append_unknown=True)- Building URLs works pretty much the other way round. Instead ofmatch you call build and pass it the endpoint and a dict ofarguments for the placeholders.
The build function also accepts an argument called force_external_which, if you set it to _True will force external URLs. Per defaultexternal URLs (include the server name) will only be used if thetarget URL is on a different subdomain.
- >>> m = Map([
- ... Rule('/', endpoint='index'),
- ... Rule('/downloads/', endpoint='downloads/index'),
- ... Rule('/downloads/<int:id>', endpoint='downloads/show')
- ... ])
- >>> urls = m.bind("example.com", "/")
- >>> urls.build("index", {})
- '/'
- >>> urls.build("downloads/show", {'id': 42})
- '/downloads/42'
- >>> urls.build("downloads/show", {'id': 42}, force_external=True)
- 'http://example.com/downloads/42'
Because URLs cannot contain non ASCII data you will always getbytestrings back. Non ASCII characters are urlencoded with thecharset defined on the map instance.
Additional values are converted to unicode and appended to the URL asURL querystring parameters:
- >>> urls.build("index", {'q': 'My Searchstring'})
- '/?q=My+Searchstring'
When processing those additional values, lists are furthermoreinterpreted as multiple values (as perwerkzeug.datastructures.MultiDict
):
- >>> urls.build("index", {'q': ['a', 'b', 'c']})
- '/?q=a&q=b&q=c'
Passing a MultiDict
will also add multiple values:
- >>> urls.build("index", MultiDict((('p', 'z'), ('q', 'a'), ('q', 'b'))))
- '/?p=z&q=a&q=b'
If a rule does not exist when building a BuildError exception israised.
The build method accepts an argument called method which allows youto specify the method you want to have an URL built for if you havedifferent methods for the same endpoint specified.
New in version 0.6: the append_unknown parameter was added.
Parameters:
- **endpoint** – the endpoint of the URL to build.
- **values** – the values for the URL to build. Unhandled values areappended to the URL as query parameters.
- **method** – the HTTP method for the rule if there are differentURLs for different methods on the same endpoint.
- **force_external** – enforce full canonical external URLs. If the URLscheme is not provided, this will generatea protocol-relative URL.
- **append_unknown** – unknown parameters are appended to the generatedURL as query string argument. Disable thisif you want the builder to ignore those.
dispatch
(view_func, path_info=None, method=None, catch_http_exceptions=False)- Does the complete dispatching process. view_func is called withthe endpoint and a dict with the values for the view. It shouldlook up the view function, call it, and return a response objector WSGI application. http exceptions are not caught by defaultso that applications can display nicer error messages by justcatching them by hand. If you want to stick with the defaulterror messages you can pass it
catch_http_exceptions=True
andit will catch the http exceptions.
Here a small example for the dispatch usage:
- from werkzeug.wrappers import Request, Response
- from werkzeug.wsgi import responder
- from werkzeug.routing import Map, Rule
- def on_index(request):
- return Response('Hello from the index')
- url_map = Map([Rule('/', endpoint='index')])
- views = {'index': on_index}
- @responder
- def application(environ, start_response):
- request = Request(environ)
- urls = url_map.bind_to_environ(environ)
- return urls.dispatch(lambda e, v: views[e](request, **v),
- catch_http_exceptions=True)
Keep in mind that this method might return exception objects, too, souse Response.force_type
to get a response object.
Parameters:
- **view_func** – a function that is called with the endpoint asfirst argument and the value dict as second. Hasto dispatch to the actual view function with thisinformation. (see above)
- **path_info** – the path info to use for matching. Overrides thepath info specified on binding.
- **method** – the HTTP method used for matching. Overrides themethod specified on binding.
- **catch_http_exceptions** – set to _True_ to catch any of thewerkzeug <code>HTTPException</code>s.
gethost
(_domain_part)Figures out the full host name for the given domain part. Thedomain part is a subdomain in case host matching is disabled ora full host name.
makealias_redirect_url
(_path, endpoint, values, method, query_args)Internally called to make an alias redirect URL.
match
(path_info=None, method=None, return_rule=False, query_args=None)The usage is simple: you just pass the match method the currentpath info as well as the method (which defaults to GET). Thefollowing things can then happen:
- you receive a NotFound exception that indicates that no URL ismatching. A NotFound exception is also a WSGI application youcan call to get a default page not found page (happens to be thesame object as werkzeug.exceptions.NotFound)
- you receive a MethodNotAllowed exception that indicates that thereis a match for this URL but not for the current request method.This is useful for RESTful applications.
- you receive a RequestRedirect exception with a new_url_attribute. This exception is used to notify you about a requestWerkzeug requests from your WSGI application. This is for example thecase if you request
/foo
although the correct URL is/foo/
You can use the _RequestRedirect instance as response-like objectsimilar to all other subclasses of HTTPException. - you get a tuple in the form
(endpoint, arguments)
if there isa match (unless return_rule is True, in which case you get a tuplein the form(rule, arguments)
)If the path info is not passed to the match method the default pathinfo of the map is used (defaults to the root URL if not definedexplicitly).
All of the exceptions raised are subclasses of HTTPException so theycan be used as WSGI responses. They will all render generic error orredirect pages.
Here is a small example for matching:
- >>> m = Map([
- ... Rule('/', endpoint='index'),
- ... Rule('/downloads/', endpoint='downloads/index'),
- ... Rule('/downloads/<int:id>', endpoint='downloads/show')
- ... ])
- >>> urls = m.bind("example.com", "/")
- >>> urls.match("/", "GET")
- ('index', {})
- >>> urls.match("/downloads/42")
- ('downloads/show', {'id': 42})
And here is what happens on redirect and missing URLs:
- >>> urls.match("/downloads")
- Traceback (most recent call last):
- ...
- RequestRedirect: http://example.com/downloads/
- >>> urls.match("/missing")
- Traceback (most recent call last):
- ...
- NotFound: 404 Not Found
Parameters:
- **path_info** – the path info to use for matching. Overrides thepath info specified on binding.
- **method** – the HTTP method used for matching. Overrides themethod specified on binding.
- **return_rule** – return the rule that matched instead of just theendpoint (defaults to _False_).
- **query_args** – optional query arguments that are used forautomatic redirects as string or dictionary. It’scurrently not possible to use the query argumentsfor URL matching.
New in version 0.6: return_rule was added.
New in version 0.7: query_args was added.
Changed in version 0.8: query_args can now also be a string.
test
(path_info=None, method=None)- Test if a rule would match. Works like match but returns True_if the URL matches, or _False if it does not exist.
Parameters:
- **path_info** – the path info to use for matching. Overrides thepath info specified on binding.
- **method** – the HTTP method used for matching. Overrides themethod specified on binding.
- class
werkzeug.routing.
Rule
(string, defaults=None, subdomain=None, methods=None, build_only=False, endpoint=None, strict_slashes=None, redirect_to=None, alias=False, host=None) A Rule represents one URL pattern. There are some options for Rule_that change the way it behaves and are passed to the _Rule constructor.Note that besides the rule-string all arguments must be keyword argumentsin order to not break the application on Werkzeug upgrades.
- string
- Rule strings basically are just normal URL paths with placeholders inthe format
<converter(arguments):name>
where the converter and thearguments are optional. If no converter is defined the default_converter is used which means _string in the normal configuration.
URL rules that end with a slash are branch URLs, others are leaves.If you have strict_slashes enabled (which is the default), allbranch URLs that are matched without a trailing slash will trigger aredirect to the same URL with the missing slash appended.
The converters are defined on the Map.
- endpoint
- The endpoint for this rule. This can be anything. A reference to afunction, a string, a number etc. The preferred way is using a stringbecause the endpoint is used for URL generation.
- defaults
- An optional dict with defaults for other rules with the same endpoint.This is a bit tricky but useful if you want to have unique URLs:
- url_map = Map([
- Rule('/all/', defaults={'page': 1}, endpoint='all_entries'),
- Rule('/all/page/<int:page>', endpoint='all_entries')
- ])
If a user now visits http://example.com/all/page/1
he will beredirected to http://example.com/all/
. If redirect_defaults isdisabled on the Map instance this will only affect the URLgeneration.
- subdomain
- The subdomain rule string for this rule. If not specified the ruleonly matches for the default_subdomain of the map. If the map isnot bound to a subdomain this feature is disabled.
Can be useful if you want to have user profiles on different subdomainsand all subdomains are forwarded to your application:
- url_map = Map([
- Rule('/', subdomain='<username>', endpoint='user/homepage'),
- Rule('/stats', subdomain='<username>', endpoint='user/stats')
- ])
- methods
- A sequence of http methods this rule applies to. If not specified, allmethods are allowed. For example this can be useful if you want differentendpoints for POST and GET. If methods are defined and the pathmatches but the method matched against is not in this list or in thelist of another rule for that path the error raised is of the typeMethodNotAllowed rather than NotFound. If GET is present in thelist of methods and HEAD is not, HEAD is added automatically.
Changed in version 0.6.1: HEAD is now automatically added to the methods if GET ispresent. The reason for this is that existing code often did notwork properly in servers not rewriting HEAD to GET_automatically and it was not documented how _HEAD should betreated. This was considered a bug in Werkzeug because of that.
- strict_slashes
- Override the Map setting for strict_slashes only for this rule. Ifnot specified the Map setting is used.
- build_only
- Set this to True and the rule will never match but will create a URLthat can be build. This is useful if you have resources on a subdomainor folder that are not handled by the WSGI application (like static data)
- redirect_to
- If given this must be either a string or callable. In case of acallable it’s called with the url adapter that triggered the match andthe values of the URL as keyword arguments and has to return the targetfor the redirect, otherwise it has to be a string with placeholders inrule syntax:
- def foo_with_slug(adapter, id):
- # ask the database for the slug for the old id. this of
- # course has nothing to do with werkzeug.
- return 'foo/' + Foo.get_slug_for_id(id)
- url_map = Map([
- Rule('/foo/<slug>', endpoint='foo'),
- Rule('/some/old/url/<slug>', redirect_to='foo/<slug>'),
- Rule('/other/old/url/<int:id>', redirect_to=foo_with_slug)
- ])
When the rule is matched the routing system will raise aRequestRedirect exception with the target for the redirect.
Keep in mind that the URL will be joined against the URL root of thescript so don’t use a leading slash on the target URL unless youreally mean root of that domain.
- alias
- If enabled this rule serves as an alias for another rule with the sameendpoint and arguments.
- host
- If provided and the URL map has host matching enabled this can beused to provide a match rule for the whole host. This also meansthat the subdomain feature is disabled.
New in version 0.7: The alias and host parameters were added.
This can be useful if want to reuse an already bound URL for anothermap. See get_empty_kwargs
to override what keyword arguments areprovided to the new copy.
Rule Factories
- class
werkzeug.routing.
RuleFactory
As soon as you have more complex URL setups it’s a good idea to use rulefactories to avoid repetitive tasks. Some of them are builtin, others canbe added by subclassing RuleFactory and overriding get_rules.
- class
werkzeug.routing.
Subdomain
(subdomain, rules) - All URLs provided by this factory have the subdomain set to aspecific domain. For example if you want to use the subdomain forthe current language this can be a good setup:
- url_map = Map([
- Rule('/', endpoint='#select_language'),
- Subdomain('<string(length=2):lang_code>', [
- Rule('/', endpoint='index'),
- Rule('/about', endpoint='about'),
- Rule('/help', endpoint='help')
- ])
- ])
All the rules except for the '#select_language'
endpoint will nowlisten on a two letter long subdomain that holds the language codefor the current request.
- class
werkzeug.routing.
Submount
(path, rules) - Like Subdomain but prefixes the URL rule with a given string:
- url_map = Map([
- Rule('/', endpoint='index'),
- Submount('/blog', [
- Rule('/', endpoint='blog/index'),
- Rule('/entry/<entry_slug>', endpoint='blog/show')
- ])
- ])
Now the rule 'blog/show'
matches /blog/entry/<entry_slug>
.
- class
werkzeug.routing.
EndpointPrefix
(prefix, rules) - Prefixes all endpoints (which must be strings for this factory) withanother string. This can be useful for sub applications:
- url_map = Map([
- Rule('/', endpoint='index'),
- EndpointPrefix('blog/', [Submount('/blog', [
- Rule('/', endpoint='index'),
- Rule('/entry/<entry_slug>', endpoint='show')
- ])])
- ])
Rule Templates
- class
werkzeug.routing.
RuleTemplate
(rules) - Returns copies of the rules wrapped and expands string templates inthe endpoint, rule, defaults or subdomain sections.
Here a small example for such a rule template:
- from werkzeug.routing import Map, Rule, RuleTemplate
- resource = RuleTemplate([
- Rule('/$name/', endpoint='$name.list'),
- Rule('/$name/<int:id>', endpoint='$name.show')
- ])
- url_map = Map([resource(name='user'), resource(name='page')])
When a rule template is called the keyword arguments are used toreplace the placeholders in all the string parameters.
Custom Converters
You can add custom converters that add behaviors not provided by thebuilt-in converters. To make a custom converter, subclassBaseConverter
then pass the new class to the Map
converters
parameter, or add it tourl_map.converters
.
The converter should have a regex
attribute with a regularexpression to match with. If the converter can take arguments in a URLrule, it should accept them in its init
method.
It can implement a to_python
method to convert the matched string tosome other object. This can also do extra validation that wasn’tpossible with the regex
attribute, and should raise awerkzeug.routing.ValidationError
in that case. Raising any othererrors will cause a 500 error.
It can implement a to_url
method to convert a Python object to astring when building a URL. Any error raised here will be converted to awerkzeug.routing.BuildError
and eventually cause a 500 error.
This example implements a BooleanConverter
that will match thestrings "yes"
, "no"
, and "maybe"
, returning a random valuefor "maybe"
.
- from random import randrange
- from werkzeug.routing import BaseConverter, ValidationError
- class BooleanConverter(BaseConverter):
- regex = r"(?:yes|no|maybe)"
- def __init__(self, url_map, maybe=False):
- super(BooleanConverter, self).__init__(url_map)
- self.maybe = maybe
- def to_python(self, value):
- if value == "maybe":
- if self.maybe:
- return not randrange(2)
- raise ValidationError
- return value == 'yes'
- def to_url(self, value):
- return "yes" if value else "no"
- from werkzeug.routing import Map, Rule
- url_map = Map([
- Rule("/vote/<bool:werkzeug_rocks>", endpoint="vote"),
- Rule("/guess/<bool(maybe=True):foo>", endpoint="guess")
- ], converters={'bool': BooleanConverter})
If you want to change the default converter, assign a differentconverter to the "default"
key.
Host Matching
New in version 0.7.
Starting with Werkzeug 0.7 it’s also possible to do matching on the wholehost names instead of just the subdomain. To enable this feature you needto pass hostmatching=True
to the Map
constructor and providethe _host argument to all routes:
- url_map = Map([
- Rule('/', endpoint='www_index', host='www.example.com'),
- Rule('/', endpoint='help_index', host='help.example.com')
- ], host_matching=True)
Variable parts are of course also possible in the host section:
- url_map = Map([
- Rule('/', endpoint='www_index', host='www.example.com'),
- Rule('/', endpoint='user_index', host='<user>.example.com')
- ], host_matching=True)