diff options
| author | Carlton Gibson | 2014-06-24 10:30:08 +0200 | 
|---|---|---|
| committer | Carlton Gibson | 2014-06-24 10:30:08 +0200 | 
| commit | d98245ac2234c2377a6243f8314b31fd68c902af (patch) | |
| tree | 5fa88ae09d97a25e20d0dbf254ad028ef4351bca /docs | |
| parent | 3f727ce738776838d8420450ce28485954fbb097 (diff) | |
| parent | 2489e38a06f575aa144644eee683bd87f20186ef (diff) | |
| download | django-rest-framework-d98245ac2234c2377a6243f8314b31fd68c902af.tar.bz2 | |
Merge branch '2.4.0' of github.com:tomchristie/django-rest-framework into #1559
Conflicts:
	docs/topics/release-notes.md
Diffstat (limited to 'docs')
| -rwxr-xr-x | docs/api-guide/authentication.md | 2 | ||||
| -rw-r--r-- | docs/api-guide/fields.md | 7 | ||||
| -rwxr-xr-x | docs/api-guide/generic-views.md | 2 | ||||
| -rw-r--r-- | docs/api-guide/routers.md | 115 | ||||
| -rw-r--r-- | docs/api-guide/serializers.md | 8 | ||||
| -rw-r--r-- | docs/api-guide/settings.md | 6 | ||||
| -rw-r--r-- | docs/api-guide/throttling.md | 13 | ||||
| -rw-r--r-- | docs/api-guide/viewsets.md | 28 | ||||
| -rw-r--r-- | docs/index.md | 16 | ||||
| -rw-r--r-- | docs/topics/2.4-accouncement.md | 5 | ||||
| -rw-r--r-- | docs/topics/contributing.md | 2 | ||||
| -rw-r--r-- | docs/topics/release-notes.md | 53 | ||||
| -rw-r--r-- | docs/tutorial/6-viewsets-and-routers.md | 8 | 
13 files changed, 188 insertions, 77 deletions
| diff --git a/docs/api-guide/authentication.md b/docs/api-guide/authentication.md index 0bddd0d0..ad6257dd 100755 --- a/docs/api-guide/authentication.md +++ b/docs/api-guide/authentication.md @@ -119,7 +119,7 @@ Unauthenticated responses that are denied permission will result in an `HTTP 401  This authentication scheme uses a simple token-based HTTP Authentication scheme.  Token authentication is appropriate for client-server setups, such as native desktop and mobile clients. -To use the `TokenAuthentication` scheme, include `rest_framework.authtoken` in your `INSTALLED_APPS` setting: +To use the `TokenAuthentication` scheme you'll need to [configure the authentication classes](#setting-the-authentication-scheme) to include `TokenAuthentication`, and additionally include `rest_framework.authtoken` in your `INSTALLED_APPS` setting:      INSTALLED_APPS = (          ... diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 67fa65d2..4825d9c8 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -164,11 +164,12 @@ Corresponds to `django.db.models.fields.BooleanField`.  ## CharField  A text representation, optionally validates the text to be shorter than `max_length` and longer than `min_length`. +If `allow_none` is `False` (default), `None` values will be converted to an empty string.  Corresponds to `django.db.models.fields.CharField`  or `django.db.models.fields.TextField`. -**Signature:** `CharField(max_length=None, min_length=None)` +**Signature:** `CharField(max_length=None, min_length=None, allow_none=False)`  ## URLField @@ -184,7 +185,9 @@ Corresponds to `django.db.models.fields.SlugField`.  ## ChoiceField -A field that can accept a value out of a limited set of choices. +A field that can accept a value out of a limited set of choices. Optionally takes a `blank_display_value` parameter that customizes the display value of an empty choice. + +**Signature:** `ChoiceField(choices=(), blank_display_value=None)`  ## EmailField diff --git a/docs/api-guide/generic-views.md b/docs/api-guide/generic-views.md index 7d06f246..bb748981 100755 --- a/docs/api-guide/generic-views.md +++ b/docs/api-guide/generic-views.md @@ -187,7 +187,7 @@ Remember that the `pre_save()` method is not called by `GenericAPIView` itself,  You won't typically need to override the following methods, although you might need to call into them if you're writing custom views using `GenericAPIView`.  * `get_serializer_context(self)` - Returns a dictionary containing any extra context that should be supplied to the serializer.  Defaults to including `'request'`, `'view'` and `'format'` keys. -* `get_serializer(self, instance=None, data=None, files=None, many=False, partial=False)` - Returns a serializer instance. +* `get_serializer(self, instance=None, data=None, files=None, many=False, partial=False, allow_add_remove=False)` - Returns a serializer instance.  * `get_pagination_serializer(self, page)` - Returns a serializer instance to use with paginated data.  * `paginate_queryset(self, queryset)` - Paginate a queryset if required, either returning a page object, or `None` if pagination is not configured for this view.  * `filter_queryset(self, queryset)` - Given a queryset, filter it with whichever filter backends are in use, returning a new queryset. diff --git a/docs/api-guide/routers.md b/docs/api-guide/routers.md index 7efc140a..819cf980 100644 --- a/docs/api-guide/routers.md +++ b/docs/api-guide/routers.md @@ -51,36 +51,41 @@ This means you'll need to explicitly set the `base_name` argument when registeri  ### Extra link and actions -Any methods on the viewset decorated with `@link` or `@action` will also be routed. +Any methods on the viewset decorated with `@detail_route` or `@list_route` will also be routed.  For example, given a method like this on the `UserViewSet` class: -	from myapp.permissions import IsAdminOrIsSelf -    from rest_framework.decorators import action - -    @action(permission_classes=[IsAdminOrIsSelf]) -    def set_password(self, request, pk=None): +    from myapp.permissions import IsAdminOrIsSelf +    from rest_framework.decorators import detail_route +     +    class UserViewSet(ModelViewSet):          ... +         +        @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf]) +        def set_password(self, request, pk=None): +            ...  The following URL pattern would additionally be generated:  * URL pattern: `^users/{pk}/set_password/$`  Name: `'user-set-password'` +For more information see the viewset documentation on [marking extra actions for routing][route-decorators]. +  # API Guide  ## SimpleRouter -This router includes routes for the standard set of `list`, `create`, `retrieve`, `update`, `partial_update` and `destroy` actions.  The viewset can also mark additional methods to be routed, using the `@link` or `@action` decorators. +This router includes routes for the standard set of `list`, `create`, `retrieve`, `update`, `partial_update` and `destroy` actions.  The viewset can also mark additional methods to be routed, using the `@detail_route` or `@list_route` decorators.  <table border=1>      <tr><th>URL Style</th><th>HTTP Method</th><th>Action</th><th>URL Name</th></tr>      <tr><td rowspan=2>{prefix}/</td><td>GET</td><td>list</td><td rowspan=2>{basename}-list</td></tr></tr>      <tr><td>POST</td><td>create</td></tr> +    <tr><td>{prefix}/{methodname}/</td><td>GET, or as specified by `methods` argument</td><td>`@list_route` decorated method</td><td>{basename}-{methodname}</td></tr>      <tr><td rowspan=4>{prefix}/{lookup}/</td><td>GET</td><td>retrieve</td><td rowspan=4>{basename}-detail</td></tr></tr>      <tr><td>PUT</td><td>update</td></tr>      <tr><td>PATCH</td><td>partial_update</td></tr>      <tr><td>DELETE</td><td>destroy</td></tr> -    <tr><td rowspan=2>{prefix}/{lookup}/{methodname}/</td><td>GET</td><td>@link decorated method</td><td rowspan=2>{basename}-{methodname}</td></tr> -    <tr><td>POST</td><td>@action decorated method</td></tr> +    <tr><td>{prefix}/{lookup}/{methodname}/</td><td>GET, or as specified by `methods` argument</td><td>`@detail_route` decorated method</td><td>{basename}-{methodname}</td></tr>  </table>  By default the URLs created by `SimpleRouter` are appended with a trailing slash. @@ -90,6 +95,12 @@ This behavior can be modified by setting the `trailing_slash` argument to `False  Trailing slashes are conventional in Django, but are not used by default in some other frameworks such as Rails.  Which style you choose to use is largely a matter of preference, although some javascript frameworks may expect a particular routing style. +The router will match lookup values containing any characters except slashes and period characters.  For a more restrictive (or lenient) lookup pattern, set the `lookup_value_regex` attribute on the viewset.  For example, you can limit the lookup to valid UUIDs: + +    class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): +        lookup_field = 'my_model_id' +        lookup_value_regex = '[0-9a-f]{32}' +  ## DefaultRouter  This router is similar to `SimpleRouter` as above, but additionally includes a default API root view, that returns a response containing hyperlinks to all the list views.  It also generates routes for optional `.json` style format suffixes. @@ -99,12 +110,12 @@ This router is similar to `SimpleRouter` as above, but additionally includes a d      <tr><td>[.format]</td><td>GET</td><td>automatically generated root view</td><td>api-root</td></tr></tr>      <tr><td rowspan=2>{prefix}/[.format]</td><td>GET</td><td>list</td><td rowspan=2>{basename}-list</td></tr></tr>      <tr><td>POST</td><td>create</td></tr> +    <tr><td>{prefix}/{methodname}/[.format]</td><td>GET, or as specified by `methods` argument</td><td>`@list_route` decorated method</td><td>{basename}-{methodname}</td></tr>      <tr><td rowspan=4>{prefix}/{lookup}/[.format]</td><td>GET</td><td>retrieve</td><td rowspan=4>{basename}-detail</td></tr></tr>      <tr><td>PUT</td><td>update</td></tr>      <tr><td>PATCH</td><td>partial_update</td></tr>      <tr><td>DELETE</td><td>destroy</td></tr> -    <tr><td rowspan=2>{prefix}/{lookup}/{methodname}/[.format]</td><td>GET</td><td>@link decorated method</td><td rowspan=2>{basename}-{methodname}</td></tr> -    <tr><td>POST</td><td>@action decorated method</td></tr> +    <tr><td>{prefix}/{lookup}/{methodname}/[.format]</td><td>GET, or as specified by `methods` argument</td><td>`@detail_route` decorated method</td><td>{basename}-{methodname}</td></tr>  </table>  As with `SimpleRouter` the trailing slashes on the URL routes can be removed by setting the `trailing_slash` argument to `False` when instantiating the router. @@ -133,28 +144,87 @@ The arguments to the `Route` named tuple are:  **initkwargs**: A dictionary of any additional arguments that should be passed when instantiating the view.  Note that the `suffix` argument is reserved for identifying the viewset type, used when generating the view name and breadcrumb links. +## Customizing dynamic routes + +You can also customize how the `@list_route` and `@detail_route` decorators are routed. +To route either or both of these decorators, include a `DynamicListRoute` and/or `DynamicDetailRoute` named tuple in the `.routes` list. + +The arguments to `DynamicListRoute` and `DynamicDetailRoute` are: + +**url**: A string representing the URL to be routed. May include the same format strings as `Route`, and additionally accepts the `{methodname}` and `{methodnamehyphen}` format strings. + +**name**: The name of the URL as used in `reverse` calls. May include the following format strings: `{basename}`, `{methodname}` and `{methodnamehyphen}`. + +**initkwargs**: A dictionary of any additional arguments that should be passed when instantiating the view. +  ## Example  The following example will only route to the `list` and `retrieve` actions, and does not use the trailing slash convention. -    from rest_framework.routers import Route, SimpleRouter +    from rest_framework.routers import Route, DynamicDetailRoute, SimpleRouter -    class ReadOnlyRouter(SimpleRouter): +    class CustomReadOnlyRouter(SimpleRouter):          """          A router for read-only APIs, which doesn't use trailing slashes.          """          routes = [ -            Route(url=r'^{prefix}$', -                  mapping={'get': 'list'}, -                  name='{basename}-list', -                  initkwargs={'suffix': 'List'}), -            Route(url=r'^{prefix}/{lookup}$', -                  mapping={'get': 'retrieve'}, -                  name='{basename}-detail', -                  initkwargs={'suffix': 'Detail'}) +            Route( +            	url=r'^{prefix}$', +            	mapping={'get': 'list'}, +            	name='{basename}-list', +            	initkwargs={'suffix': 'List'} +            ), +            Route( +            	url=r'^{prefix}/{lookup}$', +               mapping={'get': 'retrieve'}, +               name='{basename}-detail', +               initkwargs={'suffix': 'Detail'} +            ), +            DynamicDetailRoute( +            	url=r'^{prefix}/{lookup}/{methodnamehyphen}$', +            	name='{basename}-{methodnamehyphen}', +            	initkwargs={} +        	)          ] -The `SimpleRouter` class provides another example of setting the `.routes` attribute. +Let's take a look at the routes our `CustomReadOnlyRouter` would generate for a simple viewset. + +`views.py`: + +    class UserViewSet(viewsets.ReadOnlyModelViewSet): +        """ +        A viewset that provides the standard actions +        """ +        queryset = User.objects.all() +        serializer_class = UserSerializer +        lookup_field = 'username' + +        @detail_route() +        def group_names(self, request): +            """ +            Returns a list of all the group names that the given +            user belongs to. +            """ +            user = self.get_object() +            groups = user.groups.all() +            return Response([group.name for group in groups]) + +`urls.py`: + +    router = CustomReadOnlyRouter() +    router.register('users', UserViewSet) +	urlpatterns = router.urls + +The following mappings would be generated... + +<table border=1> +    <tr><th>URL</th><th>HTTP Method</th><th>Action</th><th>URL Name</th></tr> +    <tr><td>/users</td><td>GET</td><td>list</td><td>user-list</td></tr> +    <tr><td>/users/{username}</td><td>GET</td><td>retrieve</td><td>user-detail</td></tr> +    <tr><td>/users/{username}/group-names</td><td>GET</td><td>group_names</td><td>user-group-names</td></tr> +</table> + +For another example of setting the `.routes` attribute, see the source code for the `SimpleRouter` class.  ## Advanced custom routers @@ -180,6 +250,7 @@ The [wq.db package][wq.db] provides an advanced [Router][wq.db-router] class (an      app.router.register_model(MyModel)  [cite]: http://guides.rubyonrails.org/routing.html +[route-decorators]: viewsets.html#marking-extra-actions-for-routing  [drf-nested-routers]: https://github.com/alanjds/drf-nested-routers  [wq.db]: http://wq.io/wq.db  [wq.db-router]: http://wq.io/docs/app.py diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index 7ee060af..cedf1ff7 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -73,8 +73,8 @@ Sometimes when serializing objects, you may not want to represent everything exa  If you need to customize the serialized value of a particular field, you can do this by creating a `transform_<fieldname>` method. For example if you needed to render some markdown from a text field: -    description = serializers.TextField() -    description_html = serializers.TextField(source='description', read_only=True) +    description = serializers.CharField() +    description_html = serializers.CharField(source='description', read_only=True)      def transform_description_html(self, obj, value):          from django.contrib.markup.templatetags.markup import markdown @@ -464,7 +464,7 @@ For more specific requirements such as specifying a different lookup for each fi              model = Account              fields = ('url', 'account_name', 'users', 'created') -## Overiding the URL field behavior +## Overriding the URL field behavior  The name of the URL field defaults to 'url'.  You can override this globally, by using the `URL_FIELD_NAME` setting. @@ -478,7 +478,7 @@ You can also override this on a per-serializer basis by using the `url_field_nam  **Note**: The generic view implementations normally generate a `Location` header in response to successful `POST` requests.  Serializers using `url_field_name` option will not have this header automatically included by the view.  If you need to do so you will ned to also override the view's `get_success_headers()` method. -You can also overide the URL field's view name and lookup field without overriding the field explicitly, by using the `view_name` and `lookup_field` options, like so: +You can also override the URL field's view name and lookup field without overriding the field explicitly, by using the `view_name` and `lookup_field` options, like so:      class AccountSerializer(serializers.HyperlinkedModelSerializer):          class Meta: diff --git a/docs/api-guide/settings.md b/docs/api-guide/settings.md index c979019f..8bde4d87 100644 --- a/docs/api-guide/settings.md +++ b/docs/api-guide/settings.md @@ -377,5 +377,11 @@ The name of a parameter in the URL conf that may be used to provide a format suf  Default: `'format'` +#### NUM_PROXIES + +An integer of 0 or more, that may be used to specify the number of application proxies that the API runs behind.  This allows throttling to more accurately identify client IP addresses.  If set to `None` then less strict IP matching will be used by the throttle classes. + +Default: `None` +  [cite]: http://www.python.org/dev/peps/pep-0020/  [strftime]: http://docs.python.org/2/library/time.html#time.strftime diff --git a/docs/api-guide/throttling.md b/docs/api-guide/throttling.md index b7c320f0..d223f9b3 100644 --- a/docs/api-guide/throttling.md +++ b/docs/api-guide/throttling.md @@ -35,7 +35,7 @@ The default throttling policy may be set globally, using the `DEFAULT_THROTTLE_C          'DEFAULT_THROTTLE_RATES': {              'anon': '100/day',              'user': '1000/day' -        }         +        }      }  The rate descriptions used in `DEFAULT_THROTTLE_RATES` may include `second`, `minute`, `hour` or `day` as the throttle period. @@ -66,6 +66,16 @@ Or, if you're using the `@api_view` decorator with function based views.          }          return Response(content) +## How clients are identified + +The `X-Forwarded-For` and `Remote-Addr` HTTP headers are used to uniquely identify client IP addresses for throttling.  If the `X-Forwarded-For` header is present then it will be used, otherwise the value of the `Remote-Addr` header will be used. + +If you need to strictly identify unique client IP addresses, you'll need to first configure the number of application proxies that the API runs behind by setting the `NUM_PROXIES` setting.  This setting should be an integer of zero or more.  If set to non-zero then the client IP will be identified as being the last IP address in the `X-Forwarded-For` header, once any application proxy IP addresses have first been excluded.  If set to zero, then the `Remote-Addr` header will always be used as the identifying IP address. + +It is important to understand that if you configure the `NUM_PROXIES` setting, then all clients behind a unique [NAT'd](http://en.wikipedia.org/wiki/Network_address_translation) gateway will be treated as a single client. + +Further context on how the `X-Forwarded-For` header works, and identifing a remote client IP can be [found here][identifing-clients]. +  ## Setting up the cache  The throttle classes provided by REST framework use Django's cache backend.  You should make sure that you've set appropriate [cache settings][cache-setting].  The default value of `LocMemCache` backend should be okay for simple setups.  See Django's [cache documentation][cache-docs] for more details. @@ -178,5 +188,6 @@ The following is an example of a rate throttle, that will randomly throttle 1 in  [cite]: https://dev.twitter.com/docs/error-codes-responses  [permissions]: permissions.md +[identifing-clients]: http://oxpedia.org/wiki/index.php?title=AppSuite:Grizzly#Multiple_Proxies_in_front_of_the_cluster  [cache-setting]: https://docs.djangoproject.com/en/dev/ref/settings/#caches  [cache-docs]: https://docs.djangoproject.com/en/dev/topics/cache/#setting-up-the-cache diff --git a/docs/api-guide/viewsets.md b/docs/api-guide/viewsets.md index 23b16575..dc5d01a2 100644 --- a/docs/api-guide/viewsets.md +++ b/docs/api-guide/viewsets.md @@ -70,7 +70,7 @@ There are two main advantages of using a `ViewSet` class over using a `View` cla  Both of these come with a trade-off.  Using regular views and URL confs is more explicit and gives you more control.  ViewSets are helpful if you want to get up and running quickly, or when you have a large API and you want to enforce a consistent URL configuration throughout. -## Marking extra methods for routing +## Marking extra actions for routing  The default routers included with REST framework will provide routes for a standard set of create/retrieve/update/destroy style operations, as shown below: @@ -101,14 +101,16 @@ The default routers included with REST framework will provide routes for a stand          def destroy(self, request, pk=None):              pass -If you have ad-hoc methods that you need to be routed to, you can mark them as requiring routing using the `@link` or `@action` decorators.  The `@link` decorator will route `GET` requests, and the `@action` decorator will route `POST` requests. +If you have ad-hoc methods that you need to be routed to, you can mark them as requiring routing using the `@detail_route` or `@list_route` decorators. + +The `@detail_route` decorator contains `pk` in its URL pattern and is intended for methods which require a single instance. The `@list_route` decorator is intended for methods which operate on a list of objects.  For example:      from django.contrib.auth.models import User -    from rest_framework import viewsets      from rest_framework import status -    from rest_framework.decorators import action +    from rest_framework import viewsets +    from rest_framework.decorators import detail_route, list_route      from rest_framework.response import Response      from myapp.serializers import UserSerializer, PasswordSerializer @@ -119,7 +121,7 @@ For example:          queryset = User.objects.all()          serializer_class = UserSerializer -        @action() +        @detail_route(methods=['post'])          def set_password(self, request, pk=None):              user = self.get_object()              serializer = PasswordSerializer(data=request.DATA) @@ -131,21 +133,27 @@ For example:                  return Response(serializer.errors,                                  status=status.HTTP_400_BAD_REQUEST) -The `@action` and `@link` decorators can additionally take extra arguments that will be set for the routed view only.  For example... +        @list_route() +        def recent_users(self, request): +            recent_users = User.objects.all().order('-last_login') +            page = self.paginate_queryset(recent_users) +            serializer = self.get_pagination_serializer(page) +            return Response(serializer.data) + +The decorators can additionally take extra arguments that will be set for the routed view only.  For example... -        @action(permission_classes=[IsAdminOrIsSelf]) +        @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf])          def set_password(self, request, pk=None):             ... -The `@action` decorator will route `POST` requests by default, but may also accept other HTTP methods, by using the `method` argument.  For example: +The `@action` decorator will route `POST` requests by default, but may also accept other HTTP methods, by using the `methods` argument.  For example: -        @action(methods=['POST', 'DELETE']) +        @detail_route(methods=['post', 'delete'])          def unset_password(self, request, pk=None):             ...  The two new actions will then be available at the urls `^users/{pk}/set_password/$` and `^users/{pk}/unset_password/$` -  ---  # API Reference diff --git a/docs/index.md b/docs/index.md index 2a4ad885..9ad647ac 100644 --- a/docs/index.md +++ b/docs/index.md @@ -206,19 +206,9 @@ General guides to using REST framework.  ## Development -If you want to work on REST framework itself, clone the repository, then... - -Build the docs: - -    ./mkdocs.py - -Run the tests: - -    ./rest_framework/runtests/runtests.py - -To run the tests against all supported configurations, first install [the tox testing tool][tox] globally, using `pip install tox`, then simply run `tox`: - -    tox +See the [Contribution guidelines][contributing] for information on how to clone +the repository, run the test suite and contribute changes back to REST +Framework.  ## Support diff --git a/docs/topics/2.4-accouncement.md b/docs/topics/2.4-accouncement.md new file mode 100644 index 00000000..91472b9c --- /dev/null +++ b/docs/topics/2.4-accouncement.md @@ -0,0 +1,5 @@ +* Writable nested serializers. +* List/detail routes. +* 1.3 Support dropped, install six for <=1.4.?. +* `allow_none` for char fields +* `trailing_slash = True` --> `[^/]`, `trailing_slash = False` --> `[^/.]`, becomes simply `[^/]` and `lookup_value_regex` is added. diff --git a/docs/topics/contributing.md b/docs/topics/contributing.md index 18a05050..d33843e1 100644 --- a/docs/topics/contributing.md +++ b/docs/topics/contributing.md @@ -65,7 +65,7 @@ To run the tests, clone the repository, and then:      pip install -r optionals.txt      # Run the tests -    rest_framework/runtests/runtests.py +    py.test  You can also use the excellent [tox][tox] testing tool to run the tests against all supported versions of Python and Django.  Install `tox` globally, and then simply run: diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md index 5722d45b..9c87c6c1 100644 --- a/docs/topics/release-notes.md +++ b/docs/topics/release-notes.md @@ -38,11 +38,8 @@ You can determine your currently installed version using `pip freeze`:  --- -## 2.3.x series - -### 2.3.x +### 2.4.0 -**Date**: April 2014  * Added compatibility with Django 1.7's native migrations.    **IMPORTANT**: In order to continue to use south with Django <1.7 you **must** provide @@ -51,21 +48,41 @@ You can determine your currently installed version using `pip freeze`:          SOUTH_MIGRATION_MODULES = {                  'authtoken': 'rest_framework.authtoken.south_migrations',          } +* Use py.test +* `@detail_route` and `@list_route` decorators replace `@action` and `@link`. +* `six` no longer bundled.  For Django <= 1.4.1, install `six` package. +* Support customizable view name and description functions, using the `VIEW_NAME_FUNCTION` and `VIEW_DESCRIPTION_FUNCTION` settings. +* Added `NUM_PROXIES` setting for smarter client IP identification. +* Added `MAX_PAGINATE_BY` setting and `max_paginate_by` generic view attribute. +* Added `cache` attribute to throttles to allow overriding of default cache. +* Bugfix: `?page_size=0` query parameter now falls back to default page size for view, instead of always turning pagination off. + + +## 2.3.x series + -* Fix nested serializers linked through a backward foreign key relation -* Fix bad links for the `BrowsableAPIRenderer` with `YAMLRenderer` -* Add `UnicodeYAMLRenderer` that extends `YAMLRenderer` with unicode -* Fix `parse_header` argument convertion -* Fix mediatype detection under Python3 -* Web browseable API now offers blank option on dropdown when the field is not required -* `APIException` representation improved for logging purposes -* Allow source="*" within nested serializers -* Better support for custom oauth2 provider backends -* Fix field validation if it's optional and has no value -* Add `SEARCH_PARAM` and `ORDERING_PARAM` -* Fix `APIRequestFactory` to support arguments within the url string for GET -* Allow three transport modes for access tokens when accessing a protected resource -* Fix `Request`'s `QueryDict` encoding +### 2.3.14 + +**Date**: 12th June 2014 + +* **Security fix**: Escape request path when it is include as part of the login and logout links in the browsable API. +* `help_text` and `verbose_name` automatically set for related fields on `ModelSerializer`. +* Fix nested serializers linked through a backward foreign key relation. +* Fix bad links for the `BrowsableAPIRenderer` with `YAMLRenderer`. +* Add `UnicodeYAMLRenderer` that extends `YAMLRenderer` with unicode. +* Fix `parse_header` argument convertion. +* Fix mediatype detection under Python 3. +* Web browseable API now offers blank option on dropdown when the field is not required. +* `APIException` representation improved for logging purposes. +* Allow source="*" within nested serializers. +* Better support for custom oauth2 provider backends. +* Fix field validation if it's optional and has no value. +* Add `SEARCH_PARAM` and `ORDERING_PARAM`. +* Fix `APIRequestFactory` to support arguments within the url string for GET. +* Allow three transport modes for access tokens when accessing a protected resource. +* Fix `QueryDict` encoding on request objects. +* Ensure throttle keys do not contain spaces, as those are invalid if using `memcached`. +* Support `blank_display_value` on `ChoiceField`.  ### 2.3.13 diff --git a/docs/tutorial/6-viewsets-and-routers.md b/docs/tutorial/6-viewsets-and-routers.md index 04b42f2e..b2019520 100644 --- a/docs/tutorial/6-viewsets-and-routers.md +++ b/docs/tutorial/6-viewsets-and-routers.md @@ -25,7 +25,7 @@ Here we've used the `ReadOnlyModelViewSet` class to automatically provide the de  Next we're going to replace the `SnippetList`, `SnippetDetail` and `SnippetHighlight` view classes.  We can remove the three views, and again replace them with a single class. -    from rest_framework.decorators import link +    from rest_framework.decorators import detail_route      class SnippetViewSet(viewsets.ModelViewSet):          """ @@ -39,7 +39,7 @@ Next we're going to replace the `SnippetList`, `SnippetDetail` and `SnippetHighl          permission_classes = (permissions.IsAuthenticatedOrReadOnly,                                IsOwnerOrReadOnly,) -        @link(renderer_classes=[renderers.StaticHTMLRenderer]) +        @detail_route(renderer_classes=[renderers.StaticHTMLRenderer])          def highlight(self, request, *args, **kwargs):              snippet = self.get_object()              return Response(snippet.highlighted) @@ -49,9 +49,9 @@ Next we're going to replace the `SnippetList`, `SnippetDetail` and `SnippetHighl  This time we've used the `ModelViewSet` class in order to get the complete set of default read and write operations. -Notice that we've also used the `@link` decorator to create a custom action, named `highlight`.  This decorator can be used to add any custom endpoints that don't fit into the standard `create`/`update`/`delete` style. +Notice that we've also used the `@detail_route` decorator to create a custom action, named `highlight`.  This decorator can be used to add any custom endpoints that don't fit into the standard `create`/`update`/`delete` style. -Custom actions which use the `@link` decorator will respond to `GET` requests.  We could have instead used the `@action` decorator if we wanted an action that responded to `POST` requests. +Custom actions which use the `@detail_route` decorator will respond to `GET` requests.  We can use the `methods` argument if we wanted an action that responded to `POST` requests.  ## Binding ViewSets to URLs explicitly | 
