URL Routing
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!
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 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>')
参数: |
|
---|
class 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')
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>')
参数: |
|
---|
class routing.IntegerConverter(map, fixed_digits=0, min=None, max=None)
This converter only accepts integer values:
Rule('/page/<int:page>')
This converter does not support negative values.
参数: |
|
---|
class routing.FloatConverter(map, min=None, max=None)
This converter only accepts floating point values:
Rule('/probability/<float:probability>')
This converter does not support negative values.
参数: |
|
---|
class routing.UUIDConverter(map)
This converter only accepts UUID strings:
Rule('/object/<uuid:identifier>')
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!
参数: |
|
---|
0.5 新版功能: sort_parameters and sort_key was added.
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(rulefactory)
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.
参数: |
|
---|
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.
参数: |
|
---|
iter_rules(endpoint=None)
Iterate over all rules or the rules of an endpoint.
参数: | endpoint – if provided only the rules for that endpointare returned. |
---|---|
返回: | an iterator |
update()
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.
allowed_methods(path_info=None)
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})
'/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'
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.
参数: |
|
---|
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.
参数: |
|
---|
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.
get_host(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.
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
参数: |
|
---|
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.
参数: |
|
---|
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.
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 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.
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.
在 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.
empty()
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.
get_rules(map)
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