all works

This commit is contained in:
Suby Raman 2017-02-02 12:52:48 -05:00
parent 7c09ec29f7
commit f9056099f9
6 changed files with 105 additions and 3 deletions

View File

@ -158,3 +158,22 @@ app.blueprint(blueprint_v2)
app.run(host='0.0.0.0', port=8000, debug=True) app.run(host='0.0.0.0', port=8000, debug=True)
``` ```
## URL Building with `url_for`
If you wish to generate a URL for a route inside of a blueprint, remember that the endpoint name
takes the format `<blueprint_name>.<handler_name>`. For example:
```
@blueprint_v1.route('/')
async def root(request):
url = app.url_for('v1.post_handler', post_id=5)
return redirect(url)
@blueprint_v1.route('/post/<post_id>')
async def post_handler(request, post_id):
return text('Post {} in Blueprint V1'.format(post_id))
```

View File

@ -67,7 +67,7 @@ app.add_route(NameView.as_view(), '/<name>')
If you want to add any decorators to the class, you can set the `decorators` If you want to add any decorators to the class, you can set the `decorators`
class variable. These will be applied to the class when `as_view` is called. class variable. These will be applied to the class when `as_view` is called.
``` ```python
class ViewWithDecorator(HTTPMethodView): class ViewWithDecorator(HTTPMethodView):
decorators = [some_decorator_here] decorators = [some_decorator_here]
@ -77,6 +77,27 @@ class ViewWithDecorator(HTTPMethodView):
app.add_route(ViewWithDecorator.as_view(), '/url') app.add_route(ViewWithDecorator.as_view(), '/url')
``` ```
#### URL Building
If you wish to build a URL for an HTTPMethodView, remember that the class name will be the endpoint
that you will pass into `url_for`. For example:
```python
@app.route('/')
def index(request):
url = app.url_for('SpecialClassView')
return redirect(url)
class SpecialClassView(HTTPMethodView):
def get(self, request):
return text('Hello from the Special Class View!')
app.add_route(SpecialClassView.as_view(), '/special_class_view')
```
## Using CompositionView ## Using CompositionView
As an alternative to the `HTTPMethodView`, you can use `CompositionView` to As an alternative to the `HTTPMethodView`, you can use `CompositionView` to
@ -106,3 +127,5 @@ view.add(['POST', 'PUT'], lambda request: text('I am a post/put method'))
# Use the new view to handle requests to the base URL # Use the new view to handle requests to the base URL
app.add_route(view, '/') app.add_route(view, '/')
``` ```
Note: currently you cannot build a URL for a CompositionView using `url_for`.

View File

@ -119,3 +119,35 @@ app.add_route(handler1, '/test')
app.add_route(handler2, '/folder/<name>') app.add_route(handler2, '/folder/<name>')
app.add_route(person_handler2, '/person/<name:[A-z]>', methods=['GET']) app.add_route(person_handler2, '/person/<name:[A-z]>', methods=['GET'])
``` ```
## URL building with `url_for`.
Sanic provides a `url_for` method, to generate URLs based on the handler method name. This is useful if you want to avoid hardcoding url paths into your app; instead, you can just reference the handler name. For example:
```
@app.route('/')
async def index(request):
# generate a URL for the endpoint `post_handler`
url = app.url_for('post_handler', post_id=5)
# the URL is `/posts/5`, redirect to it
return redirect(url)
@app.route('/posts/<post_id>')
async def post_handler(request, post_id):
return text('Post - {}'.format(post_id))
```
Other things to keep in mind when using `url_for`:
- Keyword arguments passed to `url_for` that are not request parameters will be included in the URL's query string. For example:
```
url = app.url_for('post_handler', post_id=5, arg_one='one', arg_two='two')
# /posts/5?arg_one=one&arg_two=two
```
- All valid parameters must be passed to `url_for` to build a URL. If a parameter is not supplied, or if a parameter does not match the specified type, a `URLBuildError` will be thrown.

View File

@ -17,3 +17,5 @@ app.static('/the_best.png', '/home/ubuntu/test.png')
app.run(host="0.0.0.0", port=8000) app.run(host="0.0.0.0", port=8000)
``` ```
Note: currently you cannot build a URL for a static file using `url_for`.

View File

@ -195,6 +195,26 @@ class Sanic:
return self.blueprint(*args, **kwargs) return self.blueprint(*args, **kwargs)
def url_for(self, view_name: str, **kwargs): def url_for(self, view_name: str, **kwargs):
"""Builds a URL based on a view name and the values provided.
In order to build a URL, all request parameters must be supplied as
keyword arguments, and each parameter must pass the test for the
specified parameter type. If these conditions are not met, a
`URLBuildError` will be thrown.
Keyword arguments that are not request parameters will be included in
the output URL's query string.
:param view_name: A string referencing the view name
:param **kwargs: keys and values that are used to build request
parameters and query string arguments.
:return: the built URL
Raises:
URLBuildError
"""
# find the route by the supplied view name
uri, route = self.router.find_route_by_view_name(view_name) uri, route = self.router.find_route_by_view_name(view_name)
if not uri or not route: if not uri or not route:
@ -203,15 +223,18 @@ class Sanic:
view_name)) view_name))
out = uri out = uri
# find all the parameters we will need to build in the URL
matched_params = re.findall( matched_params = re.findall(
self.router.parameter_pattern, uri) self.router.parameter_pattern, uri)
for match in matched_params: for match in matched_params:
name, _type, pattern = self.router.parse_parameter_string( name, _type, pattern = self.router.parse_parameter_string(
match) match)
# we only want to match against each individual parameter
specific_pattern = '^{}$'.format(pattern) specific_pattern = '^{}$'.format(pattern)
supplied_param = None supplied_param = None
if kwargs.get(name): if kwargs.get(name):
supplied_param = kwargs.get(name) supplied_param = kwargs.get(name)
del kwargs[name] del kwargs[name]
@ -221,6 +244,8 @@ class Sanic:
name)) name))
supplied_param = str(supplied_param) supplied_param = str(supplied_param)
# determine if the parameter supplied by the caller passes the test
# in the URL
passes_pattern = re.match(specific_pattern, supplied_param) passes_pattern = re.match(specific_pattern, supplied_param)
if not passes_pattern: if not passes_pattern:
@ -236,6 +261,7 @@ class Sanic:
supplied_param, name, pattern)) supplied_param, name, pattern))
raise URLBuildError(msg) raise URLBuildError(msg)
# replace the parameter in the URL with the supplied value
replacement_regex = '(<{}.*?>)'.format(name) replacement_regex = '(<{}.*?>)'.format(name)
out = re.sub( out = re.sub(

View File

@ -3,7 +3,7 @@ from urllib.parse import urlsplit, parse_qsl
from sanic import Sanic from sanic import Sanic
from sanic.response import text from sanic.response import text
from sanic.views import HTTPMethodView, CompositionView from sanic.views import HTTPMethodView
from sanic.blueprints import Blueprint from sanic.blueprints import Blueprint
from sanic.utils import sanic_endpoint_test from sanic.utils import sanic_endpoint_test
from sanic.exceptions import URLBuildError from sanic.exceptions import URLBuildError