URL Routing¶
When it comes to combining multiple controller or view functions (however
you want to call them), you need a dispatcher. A simple way would be
applying regular expression tests on PATH_INFO
and call registered
callback functions that return the value.
Werkzeug provides a much more powerful system, similar to Routes. All the
objects mentioned on this page must be imported from werkzeug.routing
, not
from 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 [f'Rule points to {endpoint!r} with arguments {args!r}'.encode()]
So what does that do? First of all we create a new Map
which stores
a bunch of URL rules. Then we pass it a list of Rule
objects.
Each Rule
object is instantiated with a string that represents a rule
and an endpoint which will be the alias for what view the rule represents.
Multiple rules can have the same endpoint, but should have different arguments
to 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 will
return a new MapAdapter
. This url_map adapter can then be used to match
or 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 exceptions
NotFound
, MethodNotAllowed
,
or RequestRedirect
. For more details about those
exceptions have a look at the documentation of the MapAdapter.match()
method.
Rule Format¶
Rule strings are URL paths with placeholders for variable parts in the
format <converter(arguments):name>
. converter
and arguments
(with parentheses) are optional. If no converter is given, the
default
converter is used (string
by default). The available
converters are discussed below.
Rules that end with a slash are “branches”, others are “leaves”. If
strict_slashes
is enabled (the default), visiting a branch URL
without a trailing slash will redirect to the URL with a slash appended.
Many HTTP servers merge consecutive slashes into one when receiving
requests. If merge_slashes
is enabled (the default), rules will
merge slashes in non-variable parts when matching and building. Visiting
a URL with consecutive slashes will redirect to the URL with slashes
merged. If you want to disable merge_slashes
for a Rule
or
Map
, you’ll also need to configure your web server
appropriately.
Built-in Converters¶
Converters for common types of URL variables are built-in. The available
converters can be overridden or extended through Map.converters
.
- class werkzeug.routing.UnicodeConverter(map, minlength=1, maxlength=None, length=None)¶
This converter is the default converter and accepts any string but only 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>')
- class werkzeug.routing.PathConverter(map, *args, **kwargs)¶
Like the default
UnicodeConverter
, but it also matches slashes. This is useful for wikis and similar applications:Rule('/<path:wikipage>') Rule('/<path:wikipage>/edit')
- class werkzeug.routing.AnyConverter(map, *items)¶
Matches one of the items provided. Items can either be Python identifiers or strings:
Rule('/<any(about, help, imprint, class, "foo,bar"):page_name>')
- Parameters:
Changelog
Changed in version 2.2: Value is validated when building a URL.
- 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:
fixed_digits (int) – The number of fixed digits in the URL. If you set this to
4
for example, the rule will only match if the URL looks like/0001/
. The default is variable length.min (int | None) – The minimal value.
max (int | None) – The maximal value.
signed (bool) – Allow signed (negative) values.
Changelog
Added 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:
Changelog
Added in version 0.15: The
signed
parameter.
Maps, Rules and Adapters¶
- class werkzeug.routing.Map(rules=None, default_subdomain='', strict_slashes=True, merge_slashes=True, redirect_defaults=True, converters=None, sort_parameters=False, sort_key=None, host_matching=False)¶
The map class stores all the URL rules and some configuration parameters. Some of the configuration values are only stored on the
Map
instance since those affect all rules, others are just defaults and can be overridden for each rule. Note that you have to specify all arguments besides therules
as keyword arguments!- Parameters:
rules (t.Iterable[RuleFactory] | None) – sequence of url rules for this map.
default_subdomain (str) – The default subdomain for rules without a subdomain defined.
strict_slashes (bool) – If a rule ends with a slash but the matched URL does not, redirect to the URL with a trailing slash.
merge_slashes (bool) – Merge consecutive slashes when matching or building URLs. Matches will redirect to the normalized URL. Slashes in variable parts are not merged.
redirect_defaults (bool) – This will redirect to the default rule if it wasn’t visited that way. This helps creating unique URLs.
converters (t.Mapping[str, type[BaseConverter]] | None) – A dict of converters that adds additional converters to the list of converters. If you redefine one converter this will override the original one.
sort_parameters (bool) – If set to
True
the url parameters are sorted. Seeurl_encode
for more details.sort_key (t.Callable[[t.Any], t.Any] | None) – The sort key function for
url_encode
.host_matching (bool) – if set to
True
it enables the host matching feature and disables the subdomain one. If enabled thehost
parameter to rules is used instead of thesubdomain
one.
Changelog
Changed in version 3.0: The
charset
andencoding_errors
parameters were removed.Changed in version 1.0: If
url_scheme
isws
orwss
, only WebSocket rules will match.Changed in version 1.0: The
merge_slashes
parameter was added.Changed in version 0.7: The
encoding_errors
andhost_matching
parameters were added.Changed in version 0.5: The
sort_parameters
andsort_key
paramters were added.- converters¶
The dictionary of converters. This can be modified after the class was created, but will only affect rules added after the modification. If the rules are defined with the list passed to the class, the
converters
parameter to the constructor has to be used instead.
- default_converters = {'any': <class 'werkzeug.routing.converters.AnyConverter'>, 'default': <class 'werkzeug.routing.converters.UnicodeConverter'>, 'float': <class 'werkzeug.routing.converters.FloatConverter'>, 'int': <class 'werkzeug.routing.converters.IntegerConverter'>, 'path': <class 'werkzeug.routing.converters.PathConverter'>, 'string': <class 'werkzeug.routing.converters.UnicodeConverter'>, 'uuid': <class 'werkzeug.routing.converters.UUIDConverter'>}¶
A dict of default converters to be used.
- lock_class()¶
The type of lock to use when updating.
Changelog
Added in version 1.0.
- is_endpoint_expecting(endpoint, *arguments)¶
Iterate over all rules and check if the endpoint expects the arguments provided. This is for example useful if you have some URLs that expect a language code and others that do not and you want to wrap the builder a bit so that the current language code is automatically added if not provided but endpoints expect it.
- iter_rules(endpoint=None)¶
Iterate over all rules or the rules of an endpoint.
- add(rulefactory)¶
Add a new rule or factory to the map and bind it. Requires that the rule is not bound to another map.
- Parameters:
rulefactory (RuleFactory) – a
Rule
orRuleFactory
- Return type:
None
- 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 the call. Note thatscript_name
will default to'/'
if not further specified orNone
. Theserver_name
at least is a requirement because the HTTP RFC requires absolute URLs for redirects and so all redirect exceptions raised by Werkzeug will contain the full canonical URL.If no path_info is passed to
match()
it will use the default path info passed to bind. While this doesn’t really make sense for manual bind calls, it’s useful if you bind a map to a WSGI environment which already contains the path info.subdomain
will default to thedefault_subdomain
for this map if no defined. If there is nodefault_subdomain
you cannot use the subdomain feature.Changelog
Changed in version 1.0: If
url_scheme
isws
orwss
, only WebSocket rules will match.Changed in version 0.15:
path_info
defaults to'/'
ifNone
.Changed in version 0.8:
query_args
can be a string.Changed in version 0.7: Added
query_args
.
- bind_to_environ(environ, server_name=None, subdomain=None)¶
Like
bind()
but you can pass it an WSGI environment and it will fetch the information from that dictionary. Note that because of limitations in the protocol there is no way to get the current subdomain and realserver_name
from the environment. If you don’t provide it, Werkzeug will useSERVER_NAME
andSERVER_PORT
(orHTTP_HOST
if provided) as usedserver_name
with disabled subdomain feature.If
subdomain
isNone
but an environment and a server name is provided it will calculate the current subdomain automatically. Example:server_name
is'example.com'
and theSERVER_NAME
in the wsgienviron
is'staging.dev.example.com'
the calculated subdomain will be'staging.dev'
.If the object passed as environ has an environ attribute, the value of this attribute is used instead. This allows you to pass request objects. Additionally
PATH_INFO
added as a default of theMapAdapter
so that you don’t have to pass the path info to the match method.Changelog
Changed in version 1.0.0: If the passed server name specifies port 443, it will match if the incoming scheme is
https
without a port.Changed in version 1.0.0: A warning is shown when the passed server name does not match the incoming WSGI server name.
Changed in version 0.8: This will no longer raise a ValueError when an unexpected server name was passed.
Changed in version 0.5: previously this method accepted a bogus
calculate_subdomain
parameter that did not have any effect. It was removed because of that.- Parameters:
- Return type:
- update()¶
Called before matching and building to keep the compiled rules in the correct order after things changed.
- Return type:
None
- 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 does the URL matching and building based on runtime information.- Parameters:
- dispatch(view_func, path_info=None, method=None, catch_http_exceptions=False)¶
Does the complete dispatching process.
view_func
is called with the endpoint and a dict with the values for the view. It should look up the view function, call it, and return a response object or WSGI application. http exceptions are not caught by default so that applications can display nicer error messages by just catching them by hand. If you want to stick with the default error messages you can pass itcatch_http_exceptions=True
and it 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, so use
Response.force_type
to get a response object.- Parameters:
view_func (t.Callable[[str, t.Mapping[str, t.Any]], WSGIApplication]) – a function that is called with the endpoint as first argument and the value dict as second. Has to dispatch to the actual view function with this information. (see above)
path_info (str | None) – the path info to use for matching. Overrides the path info specified on binding.
method (str | None) – the HTTP method used for matching. Overrides the method specified on binding.
catch_http_exceptions (bool) – set to
True
to catch any of the werkzeugHTTPException
s.
- Return type:
WSGIApplication
- match(path_info: str | None = None, method: str | None = None, return_rule: Literal[False] = False, query_args: Mapping[str, Any] | str | None = None, websocket: bool | None = None) tuple[Any, Mapping[str, Any]] ¶
- match(path_info: str | None = None, method: str | None = None, return_rule: Literal[True] = True, query_args: Mapping[str, Any] | str | None = None, websocket: bool | None = None) tuple[Rule, Mapping[str, Any]]
The usage is simple: you just pass the match method the current path info as well as the method (which defaults to
GET
). The following things can then happen:you receive a
NotFound
exception that indicates that no URL is matching. ANotFound
exception is also a WSGI application you can call to get a default page not found page (happens to be the same object aswerkzeug.exceptions.NotFound
)you receive a
MethodNotAllowed
exception that indicates that there is a match for this URL but not for the current request method. This is useful for RESTful applications.you receive a
RequestRedirect
exception with anew_url
attribute. This exception is used to notify you about a request Werkzeug requests from your WSGI application. This is for example the case if you request/foo
although the correct URL is/foo/
You can use theRequestRedirect
instance as response-like object similar to all other subclasses ofHTTPException
.you receive a
WebsocketMismatch
exception if the only match is a WebSocket rule but the bind is an HTTP request, or if the match is an HTTP rule but the bind is a WebSocket request.you get a tuple in the form
(endpoint, arguments)
if there is a match (unlessreturn_rule
is True, in which case you get a tuple in the form(rule, arguments)
)
If the path info is not passed to the match method the default path info of the map is used (defaults to the root URL if not defined explicitly).
All of the exceptions raised are subclasses of
HTTPException
so they can be used as WSGI responses. They will all render generic error or redirect 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 the path info specified on binding.
method – the HTTP method used for matching. Overrides the method specified on binding.
return_rule – return the rule that matched instead of just the endpoint (defaults to
False
).query_args – optional query arguments that are used for automatic redirects as string or dictionary. It’s currently not possible to use the query arguments for URL matching.
websocket – Match WebSocket instead of HTTP requests. A websocket request has a
ws
orwss
url_scheme
. This overrides that detection.
Changelog
Added in version 1.0: Added
websocket
.Changed in version 0.8:
query_args
can be a string.Added in version 0.7: Added
query_args
.Added in version 0.6: Added
return_rule
.
- test(path_info=None, method=None)¶
Test if a rule would match. Works like
match
but returnsTrue
if the URL matches, orFalse
if it does not exist.
- allowed_methods(path_info=None)¶
Returns the valid methods that match for a given path.
Changelog
Added in version 0.7.
- get_host(domain_part)¶
Figures out the full host name for the given domain part. The domain part is a subdomain in case host matching is disabled or a full host name.
- make_alias_redirect_url(path, endpoint, values, method, query_args)¶
Internally called to make an alias redirect URL.
- build(endpoint, values=None, method=None, force_external=False, append_unknown=True, url_scheme=None)¶
Building URLs works pretty much the other way round. Instead of
match
you callbuild
and pass it the endpoint and a dict of arguments for the placeholders.The
build
function also accepts an argument calledforce_external
which, if you set it toTrue
will force external URLs. Per default external URLs (include the server name) will only be used if the target 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 get bytes back. Non ASCII characters are urlencoded with the charset defined on the map instance.
Additional values are converted to strings and appended to the URL as URL querystring parameters:
>>> urls.build("index", {'q': 'My Searchstring'}) '/?q=My+Searchstring'
When processing those additional values, lists are furthermore interpreted as multiple values (as per
werkzeug.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 is raised.The build method accepts an argument called
method
which allows you to specify the method you want to have an URL built for if you have different methods for the same endpoint specified.- Parameters:
endpoint (Any) – the endpoint of the URL to build.
values (Mapping[str, Any] | None) – the values for the URL to build. Unhandled values are appended to the URL as query parameters.
method (str | None) – the HTTP method for the rule if there are different URLs for different methods on the same endpoint.
force_external (bool) – enforce full canonical external URLs. If the URL scheme is not provided, this will generate a protocol-relative URL.
append_unknown (bool) – unknown parameters are appended to the generated URL as query string argument. Disable this if you want the builder to ignore those.
url_scheme (str | None) – Scheme to use in place of the bound
url_scheme
.
- Return type:
Changelog
Changed in version 2.0: Added the
url_scheme
parameter.Added in version 0.6: Added the
append_unknown
parameter.
- class werkzeug.routing.Rule(string, defaults=None, subdomain=None, methods=None, build_only=False, endpoint=None, strict_slashes=None, merge_slashes=None, redirect_to=None, alias=False, host=None, websocket=False)¶
A Rule represents one URL pattern. There are some options for
Rule
that change the way it behaves and are passed to theRule
constructor. Note that besides the rule-string all arguments must be keyword arguments in order to not break the application on Werkzeug upgrades.string
Rule strings basically are just normal URL paths with placeholders in the format
<converter(arguments):name>
where the converter and the arguments are optional. If no converter is defined thedefault
converter is used which meansstring
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), all branch URLs that are matched without a trailing slash will trigger a redirect 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 a function, a string, a number etc. The preferred way is using a string because 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
they will be redirected tohttp://example.com/all/
. Ifredirect_defaults
is disabled on theMap
instance this will only affect the URL generation.subdomain
The subdomain rule string for this rule. If not specified the rule only matches for the
default_subdomain
of the map. If the map is not bound to a subdomain this feature is disabled.Can be useful if you want to have user profiles on different subdomains and 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, all methods are allowed. For example this can be useful if you want different endpoints for
POST
andGET
. If methods are defined and the path matches but the method matched against is not in this list or in the list of another rule for that path the error raised is of the typeMethodNotAllowed
rather thanNotFound
. IfGET
is present in the list of methods andHEAD
is not,HEAD
is added automatically.strict_slashes
Override the
Map
setting forstrict_slashes
only for this rule. If not specified theMap
setting is used.merge_slashes
Override
Map.merge_slashes
for this rule.build_only
Set this to True and the rule will never match but will create a URL that can be build. This is useful if you have resources on a subdomain or 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 a callable it’s called with the url adapter that triggered the match and the values of the URL as keyword arguments and has to return the target for the redirect, otherwise it has to be a string with placeholders in rule 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 f'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 a
RequestRedirect
exception with the target for the redirect.Keep in mind that the URL will be joined against the URL root of the script so don’t use a leading slash on the target URL unless you really mean root of that domain.
alias
If enabled this rule serves as an alias for another rule with the same endpoint and arguments.
host
If provided and the URL map has host matching enabled this can be used to provide a match rule for the whole host. This also means that the subdomain feature is disabled.
websocket
If
True
, this rule is only matches for WebSocket (ws://
,wss://
) requests. By default, rules will only match for HTTP requests.
Changelog
Changed in version 2.1: Percent-encoded newlines (
%0a
), which are decoded by WSGI servers, are considered when routing instead of terminating the match early.Added in version 1.0: Added
websocket
.Added in version 1.0: Added
merge_slashes
.Added in version 0.7: Added
alias
andhost
.Changed in version 0.6.1:
HEAD
is added tomethods
ifGET
is present.
Matchers¶
Rule Factories¶
- class werkzeug.routing.RuleFactory¶
As soon as you have more complex URL setups it’s a good idea to use rule factories to avoid repetitive tasks. Some of them are builtin, others can be added by subclassing
RuleFactory
and overridingget_rules
.
- class werkzeug.routing.Subdomain(subdomain, rules)¶
All URLs provided by this factory have the subdomain set to a specific domain. For example if you want to use the subdomain for the 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 now listen on a two letter long subdomain that holds the language code for the current request.- Parameters:
subdomain (str)
rules (t.Iterable[RuleFactory])
- 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>
.- Parameters:
path (str)
rules (t.Iterable[RuleFactory])
- class werkzeug.routing.EndpointPrefix(prefix, rules)¶
Prefixes all endpoints (which must be strings for this factory) with another 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') ])]) ])
- Parameters:
prefix (str)
rules (t.Iterable[RuleFactory])
Rule Templates¶
- class werkzeug.routing.RuleTemplate(rules)¶
Returns copies of the rules wrapped and expands string templates in the 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 to replace the placeholders in all the string parameters.
- Parameters:
rules (t.Iterable[Rule])
Custom Converters¶
You can add custom converters that add behaviors not provided by the
built-in converters. To make a custom converter, subclass
BaseConverter
then pass the new class to the Map
converters
parameter, or add it to
url_map.converters
.
The converter should have a regex
attribute with a regular
expression to match with. If the converter can take arguments in a URL
rule, it should accept them in its __init__
method. The entire
regex expression will be matched as a group and used as the value for
conversion.
If a custom converter can match a forward slash, /
, it should have
the attribute part_isolating
set to False
. This will ensure
that rules using the custom converter are correctly matched.
It can implement a to_python
method to convert the matched string to
some other object. This can also do extra validation that wasn’t
possible with the regex
attribute, and should raise a
werkzeug.routing.ValidationError
in that case. Raising any other
errors will cause a 500 error.
It can implement a to_url
method to convert a Python object to a
string when building a URL. Any error raised here will be converted to a
werkzeug.routing.BuildError
and eventually cause a 500 error.
This example implements a BooleanConverter
that will match the
strings "yes"
, "no"
, and "maybe"
, returning a random value
for "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().__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 different
converter to the "default"
key.
Host Matching¶
Changelog
Added in version 0.7.
Starting with Werkzeug 0.7 it’s also possible to do matching on the whole
host names instead of just the subdomain. To enable this feature you need
to pass host_matching=True
to the Map
constructor and provide
the 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)
WebSockets¶
Changelog
Added in version 1.0.
If a Rule
is created with websocket=True
, it will only
match if the Map
is bound to a request with a url_scheme
of
ws
or wss
.
Note
Werkzeug has no further WebSocket support beyond routing. This functionality is mostly of use to ASGI projects.
url_map = Map([
Rule("/ws", endpoint="comm", websocket=True),
])
adapter = map.bind("example.org", "/ws", url_scheme="ws")
assert adapter.match() == ("comm", {})
If the only match is a WebSocket rule and the bind is HTTP (or the
only match is HTTP and the bind is WebSocket) a
WebsocketMismatch
(derives from
BadRequest
) exception is raised.
As WebSocket URLs have a different scheme, rules are always built with a
scheme and host, force_external=True
is implied.
url = adapter.build("comm")
assert url == "ws://example.org/ws"
State Machine Matching¶
The default matching algorithm uses a state machine that transitions between parts of the request path to find a match. To understand how this works consider this rule:
/resource/<id>
Firstly this rule is decomposed into two RulePart
. The first is a
static part with a content equal to resource
, the second is
dynamic and requires a regex match to [^/]+
.
A state machine is then created with an initial state that represents
the rule’s first /
. This initial state has a single, static
transition to the next state which represents the rule’s second
/
. This second state has a single dynamic transition to the final
state which includes the rule.
To match a path the matcher starts and the initial state and follows
transitions that work. Clearly a trial path of /resource/2
has the
parts ""
, resource
, and 2
which match the transitions and
hence a rule will match. Whereas /other/2
will not match as there
is no transition for the other
part from the initial state.
The only diversion from this rule is if a RulePart
is not
part-isolating i.e. it will match /
. In this case the RulePart
is considered final and represents a transition that must include all
the subsequent parts of the trial path.