URL Routing

2018-02-24 15:39 更新

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 [http://routes.groovie.org/]. All theobjects mentioned on this page must be imported from werkzeug.routing, notfrom werkzeug!


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('/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)
        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 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.


  • 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 routing.PathConverter(map)
Like the default UnicodeConverter, but it also matchesslashes. This is useful for wikis and similar applications:


class 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>')
  • map – the Map.
  • items – this function accepts the possible items as positionalarguments.

class routing.IntegerConverter(map, fixed_digits=0, min=None, max=None)
This converter only accepts integer values:


This converter does not support negative values.

  • map – the Map.
  • fixed_digits – the number of fixed digits in the URL. If you setthis to 4 for example, the application willonly match if the url looks like /0001/. Thedefault is variable length.
  • min – the minimal value.
  • max – the maximal value.

class routing.FloatConverter(map, min=None, max=None)
This converter only accepts floating point values:


This converter does not support negative values.

  • map – the Map.
  • min – the minimal value.
  • max – the maximal value.

class routing.UUIDConverter(map)
This converter only accepts UUID strings:


0.10 新版功能.

Maps, Rules and Adapters

class 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!

  • 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.

0.5 新版功能: sort_parameters and sort_key was added.

0.7 新版功能: encoding_errors and host_matching was added.

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.

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.

0.7 新版功能: query_args added

0.8 新版功能: query_args can now also be a string.

bind_to_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_NAMEin 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.

在 0.5 版更改: previously this method accepted a bogus calculate_subdomainparameter that did not have any effect. It was removed becauseof that.

在 0.8 版更改: This will no longer raise a ValueError when an unexpected servername was passed.

  • environ – a WSGI environment.
  • server_name – an optional server name hint (see above).
  • subdomain – optionally the current subdomain (see above).

default_converters = ImmutableDict({'int': <class 'routing.IntegerConverter'>, 'string': <class 'routing.UnicodeConverter'>, 'default': <class 'routing.UnicodeConverter'>, 'path': <class 'routing.PathConverter'>, 'float': <class 'routing.FloatConverter'>, 'any': <class 'routing.AnyConverter'>, 'uuid': <class 'routing.UUIDConverter'>})

0.6 新版功能: a dict of default converters to be used.

is_endpoint_expecting(endpoint, *arguments)
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.

  • endpoint – the endpoint to check.
  • arguments – this function accepts one or more argumentsas positional arguments. Each one of them ischecked.

Iterate over all rules or the rules of an endpoint.

参数: endpoint – if provided only the rules for that endpointare returned.
返回: an iterator

Called before matching and building to keep the compiled rulesin the correct order after things changed.

class routing.MapAdapter(map, server_name, script_name, subdomain, url_scheme, path_info, default_method, query_args=None)
Returned by Map.bind() or Map.bind_to_environ() and doesthe URL matching and building based on runtime information.

Returns the valid methods that match for a given path.

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_externalwhich, 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})
>>> urls.build("downloads/show", {'id': 42}, force_external=True)

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'})

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.

0.6 新版功能: the append_unknown parameter was added.

  • 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.
  • 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}

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),

Keep in mind that this method might return exception objects, too, souse Response.force_type to get a response object.

  • 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 HTTPExceptions.

get_default_redirect(rule, method, values, query_args)
A helper that returns the URL to redirect to if it finds one.This is used for default redirecting only.

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.

make_alias_redirect_url(path, endpoint, values, method, query_args)
Internally called to make an alias redirect URL.

make_redirect_url(path_info, query_args=None, domain_part=None)
Creates a 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_urlattribute. 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. The 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
  • 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.

0.6 新版功能: return_rule was added.

0.7 新版功能: query_args was added.

在 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 Trueif the URL matches, or False if it does not exist.

  • 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 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 Rulethat 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.

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 defaultconverter 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.

endpointThe 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.

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')

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.

在 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 GETautomatically and it was not documented how HEAD should betreated. This was considered a bug in Werkzeug because of that.

strict_slashesOverride the Map setting for strict_slashes only for this rule. Ifnot specified the Map setting is used.build_onlySet 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.

aliasIf enabled this rule serves as an alias for another rule with the sameendpoint and arguments.hostIf 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.

0.7 新版功能: The alias and host parameters were added.

Return an unbound copy of this rule. This can be useful if youwant to reuse an already bound URL for another map.

Rule Factories

class 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.

Subclasses of RuleFactory have to override this method and returnan iterable of rules.

class 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 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/.

class 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 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.sho