diff options
| author | Tom Christie | 2014-08-28 17:33:56 +0100 | 
|---|---|---|
| committer | Tom Christie | 2014-08-28 17:33:56 +0100 | 
| commit | 9ae5a48332cb041ef4c56b775beb9ee98df07eb0 (patch) | |
| tree | 9148e9e6669c86e622770eaa16be097467a77f14 /api-guide | |
| parent | 66f25af53a6e1815178b8a010ffd451822ffdc6e (diff) | |
| download | django-rest-framework-9ae5a48332cb041ef4c56b775beb9ee98df07eb0.tar.bz2 | |
Latest docs update
Diffstat (limited to 'api-guide')
| -rw-r--r-- | api-guide/authentication.html | 9 | ||||
| -rw-r--r-- | api-guide/fields.html | 8 | ||||
| -rw-r--r-- | api-guide/generic-views.html | 14 | ||||
| -rw-r--r-- | api-guide/routers.html | 99 | ||||
| -rw-r--r-- | api-guide/serializers.html | 3 | ||||
| -rw-r--r-- | api-guide/settings.html | 3 | ||||
| -rw-r--r-- | api-guide/throttling.html | 7 | ||||
| -rw-r--r-- | api-guide/viewsets.html | 28 | 
8 files changed, 129 insertions, 42 deletions
| diff --git a/api-guide/authentication.html b/api-guide/authentication.html index bbce2835..9b11fbe5 100644 --- a/api-guide/authentication.html +++ b/api-guide/authentication.html @@ -307,7 +307,9 @@ WSGIPassAuthorization On      'rest_framework.authtoken'  )  </code></pre> -<p>Make sure to run <code>manage.py syncdb</code> after changing your settings. The <code>authtoken</code> database tables are managed by south (see <a href="#schema-migrations">Schema migrations</a> below).</p> +<hr /> +<p><strong>Note:</strong> Make sure to run <code>manage.py syncdb</code> after changing your settings. The <code>rest_framework.authtoken</code> app provides both Django (from v1.7) and South database migrations. See <a href="#schema-migrations">Schema migrations</a> below.</p> +<hr />  <p>You'll also need to create tokens for your users.</p>  <pre class="prettyprint lang-py"><code>from rest_framework.authtoken.models import Token @@ -362,7 +364,10 @@ for user in User.objects.all():  </code></pre>  <p>Note that the default <code>obtain_auth_token</code> view explicitly uses JSON requests and responses, rather than using default renderer and parser classes in your settings.  If you need a customized version of the <code>obtain_auth_token</code> view, you can do so by overriding the <code>ObtainAuthToken</code> view class, and using that in your url conf instead.</p>  <h4 id="schema-migrations">Schema migrations</h4> -<p>The <code>rest_framework.authtoken</code> app includes a south migration that will create the authtoken table.</p> +<p>The <code>rest_framework.authtoken</code> app includes both Django native migrations (for Django versions >1.7) and South migrations (for Django versions <1.7) that will create the authtoken table.</p> +<hr /> +<p><strong>Note</strong>: From REST Framework v2.4.0 using South with Django <1.7 requires upgrading South v1.0+</p> +<hr />  <p>If you're using a <a href="https://docs.djangoproject.com/en/dev/topics/auth/customizing/#specifying-a-custom-user-model">custom user model</a> you'll need to make sure that any initial migration that creates the user table runs before the authtoken table is created.</p>  <p>You can do so by inserting a <code>needed_by</code> attribute in your user migration:</p>  <pre class="prettyprint lang-py"><code>class Migration: diff --git a/api-guide/fields.html b/api-guide/fields.html index 72ef27e4..4ca9b1fb 100644 --- a/api-guide/fields.html +++ b/api-guide/fields.html @@ -213,6 +213,7 @@ a.fusion-poweredby {  <li><a href="#drf-compound-fields">DRF Compound Fields</a></li>  <li><a href="#drf-extra-fields">DRF Extra Fields</a></li>  <li><a href="#django-rest-framework-gis">django-rest-framework-gis</a></li> +<li><a href="#django-rest-framework-hstore">django-rest-framework-hstore</a></li>                <div class="promo"> @@ -329,10 +330,11 @@ class UserSerializer(serializers.ModelSerializer):  <p>A Boolean representation.</p>  <p>Corresponds to <code>django.db.models.fields.BooleanField</code>.</p>  <h2 id="charfield">CharField</h2> -<p>A text representation, optionally validates the text to be shorter than <code>max_length</code> and longer than <code>min_length</code>.</p> +<p>A text representation, optionally validates the text to be shorter than <code>max_length</code> and longer than <code>min_length</code>. +If <code>allow_none</code> is <code>False</code> (default), <code>None</code> values will be converted to an empty string.</p>  <p>Corresponds to <code>django.db.models.fields.CharField</code>  or <code>django.db.models.fields.TextField</code>.</p> -<p><strong>Signature:</strong> <code>CharField(max_length=None, min_length=None)</code></p> +<p><strong>Signature:</strong> <code>CharField(max_length=None, min_length=None, allow_none=False)</code></p>  <h2 id="urlfield">URLField</h2>  <p>Corresponds to <code>django.db.models.fields.URLField</code>.  Uses Django's <code>django.core.validators.URLValidator</code> for validation.</p>  <p><strong>Signature:</strong> <code>URLField(max_length=200, min_length=None)</code></p> @@ -461,6 +463,8 @@ class ColourField(serializers.WritableField):  <p>The <a href="https://github.com/Hipo/drf-extra-fields">drf-extra-fields</a> package provides extra serializer fields for REST framework, including <code>Base64ImageField</code> and <code>PointField</code> classes.</p>  <h2 id="django-rest-framework-gis">django-rest-framework-gis</h2>  <p>The <a href="https://github.com/djangonauts/django-rest-framework-gis">django-rest-framework-gis</a> package provides geographic addons for django rest framework like a  <code>GeometryField</code> field and a GeoJSON serializer.</p> +<h2 id="django-rest-framework-hstore">django-rest-framework-hstore</h2> +<p>The <a href="https://github.com/djangonauts/django-rest-framework-hstore">django-rest-framework-hstore</a> package provides an <code>HStoreField</code> to support <a href="https://github.com/djangonauts/django-hstore">django-hstore</a> <code>DictionaryField</code> model field.</p>            </div><!--/span-->          </div><!--/row-->        </div><!--/.fluid-container--> diff --git a/api-guide/generic-views.html b/api-guide/generic-views.html index a9f96812..be6e19f1 100644 --- a/api-guide/generic-views.html +++ b/api-guide/generic-views.html @@ -262,7 +262,7 @@ class UserList(generics.ListCreateAPIView):          serializer = UserSerializer(queryset, many=True)          return Response(serializer.data)  </code></pre> -<p>For very simple cases you might want to pass through any class attributes using the <code>.as_view()</code> method.  For example, your URLconf might include something the following entry.</p> +<p>For very simple cases you might want to pass through any class attributes using the <code>.as_view()</code> method.  For example, your URLconf might include something like the following entry:</p>  <pre class="prettyprint lang-py"><code>url(r'^/users/', ListCreateAPIView.as_view(model=User), name='user-list')  </code></pre>  <hr /> @@ -300,7 +300,7 @@ class UserList(generics.ListCreateAPIView):  <h4 id="get_querysetself"><code>get_queryset(self)</code></h4>  <p>Returns the queryset that should be used for list views, and that should be used as the base for lookups in detail views.  Defaults to returning the queryset specified by the <code>queryset</code> attribute, or the default queryset for the model if the <code>model</code> shortcut is being used.</p>  <p>This method should always be used rather than accessing <code>self.queryset</code> directly, as <code>self.queryset</code> gets evaluated only once, and those results are cached for all subsequent requests.</p> -<p>May be overridden to provide dynamic behavior such as returning a queryset that is specific to the user making the request.</p> +<p>May be overridden to provide dynamic behavior, such as returning a queryset, that is specific to the user making the request.</p>  <p>For example:</p>  <pre class="prettyprint lang-py"><code>def get_queryset(self):      user = self.request.user @@ -308,7 +308,7 @@ class UserList(generics.ListCreateAPIView):  </code></pre>  <h4 id="get_objectself"><code>get_object(self)</code></h4>  <p>Returns an object instance that should be used for detail views.  Defaults to using the <code>lookup_field</code> parameter to filter the base queryset.</p> -<p>May be overridden to provide more complex behavior such as object lookups based on more than one URL kwarg.</p> +<p>May be overridden to provide more complex behavior, such as object lookups based on more than one URL kwarg.</p>  <p>For example:</p>  <pre class="prettyprint lang-py"><code>def get_object(self):      queryset = self.get_queryset() @@ -323,7 +323,7 @@ class UserList(generics.ListCreateAPIView):  <p>Note that if your API doesn't include any object level permissions, you may optionally exclude the <code>self.check_object_permissions</code>, and simply return the object from the <code>get_object_or_404</code> lookup.</p>  <h4 id="get_filter_backendsself"><code>get_filter_backends(self)</code></h4>  <p>Returns the classes that should be used to filter the queryset. Defaults to returning the <code>filter_backends</code> attribute.</p> -<p>May be override to provide more complex behavior with filters, as using different (or even exlusive) lists of filter_backends depending on different criteria.</p> +<p>May be overridden to provide more complex behavior with filters, such as using different (or even exlusive) lists of filter_backends depending on different criteria.</p>  <p>For example:</p>  <pre class="prettyprint lang-py"><code>def get_filter_backends(self):      if "geo_route" in self.request.QUERY_PARAMS: @@ -335,7 +335,7 @@ class UserList(generics.ListCreateAPIView):  </code></pre>  <h4 id="get_serializer_classself"><code>get_serializer_class(self)</code></h4>  <p>Returns the class that should be used for the serializer.  Defaults to returning the <code>serializer_class</code> attribute, or dynamically generating a serializer class if the <code>model</code> shortcut is being used.</p> -<p>May be override to provide dynamic behavior such as using different serializers for read and write operations, or providing different serializers to different types of users.</p> +<p>May be overridden to provide dynamic behavior, such as using different serializers for read and write operations, or providing different serializers to different types of users.</p>  <p>For example:</p>  <pre class="prettyprint lang-py"><code>def get_serializer_class(self):      if self.request.user.is_staff: @@ -344,7 +344,7 @@ class UserList(generics.ListCreateAPIView):  </code></pre>  <h4 id="get_paginate_byself"><code>get_paginate_by(self)</code></h4>  <p>Returns the page size to use with pagination.  By default this uses the <code>paginate_by</code> attribute, and may be overridden by the client if the <code>paginate_by_param</code> attribute is set.</p> -<p>You may want to override this method to provide more complex behavior such as modifying page sizes based on the media type of the response.</p> +<p>You may want to override this method to provide more complex behavior, such as modifying page sizes based on the media type of the response.</p>  <p>For example:</p>  <pre class="prettyprint lang-py"><code>def get_paginate_by(self):      if self.request.accepted_renderer.format == 'html': @@ -378,7 +378,7 @@ class UserList(generics.ListCreateAPIView):  </ul>  <hr />  <h1 id="mixins">Mixins</h1> -<p>The mixin classes provide the actions that are used to provide the basic view behavior.  Note that the mixin classes provide action methods rather than defining the handler methods such as <code>.get()</code> and <code>.post()</code> directly.  This allows for more flexible composition of behavior.</p> +<p>The mixin classes provide the actions that are used to provide the basic view behavior.  Note that the mixin classes provide action methods rather than defining the handler methods, such as <code>.get()</code> and <code>.post()</code>, directly.  This allows for more flexible composition of behavior.</p>  <h2 id="listmodelmixin">ListModelMixin</h2>  <p>Provides a <code>.list(request, *args, **kwargs)</code> method, that implements listing a queryset.</p>  <p>If the queryset is populated, this returns a <code>200 OK</code> response, with a serialized representation of the queryset as the body of the response.  The response data may optionally be paginated.</p> diff --git a/api-guide/routers.html b/api-guide/routers.html index 70dd61c4..77c6e585 100644 --- a/api-guide/routers.html +++ b/api-guide/routers.html @@ -190,6 +190,7 @@ a.fusion-poweredby {  <li><a href="#simplerouter">SimpleRouter</a></li>  <li><a href="#defaultrouter">DefaultRouter</a></li>  <li class="main"><a href="#custom-routers">Custom Routers</a></li> +<li><a href="#customizing-dynamic-routes">Customizing dynamic routes</a></li>  <li><a href="#example">Example</a></li>  <li><a href="#advanced-custom-routers">Advanced custom routers</a></li>  <li class="main"><a href="#third-party-packages">Third Party Packages</a></li> @@ -247,32 +248,36 @@ urlpatterns = router.urls  <p>This means you'll need to explicitly set the <code>base_name</code> argument when registering the viewset, as it could not be automatically determined from the model name.</p>  <hr />  <h3 id="extra-link-and-actions">Extra link and actions</h3> -<p>Any methods on the viewset decorated with <code>@link</code> or <code>@action</code> will also be routed. +<p>Any methods on the viewset decorated with <code>@detail_route</code> or <code>@list_route</code> will also be routed.  For example, given a method like this on the <code>UserViewSet</code> class:</p>  <pre class="prettyprint lang-py"><code>from myapp.permissions import IsAdminOrIsSelf -from rest_framework.decorators import action +from rest_framework.decorators import detail_route -@action(permission_classes=[IsAdminOrIsSelf]) -def set_password(self, request, pk=None): +class UserViewSet(ModelViewSet):      ... + +    @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf]) +    def set_password(self, request, pk=None): +        ...  </code></pre>  <p>The following URL pattern would additionally be generated:</p>  <ul>  <li>URL pattern: <code>^users/{pk}/set_password/$</code>  Name: <code>'user-set-password'</code></li>  </ul> +<p>For more information see the viewset documentation on <a href="viewsets.html#marking-extra-actions-for-routing">marking extra actions for routing</a>.</p>  <h1 id="api-guide">API Guide</h1>  <h2 id="simplerouter">SimpleRouter</h2> -<p>This router includes routes for the standard set of <code>list</code>, <code>create</code>, <code>retrieve</code>, <code>update</code>, <code>partial_update</code> and <code>destroy</code> actions.  The viewset can also mark additional methods to be routed, using the <code>@link</code> or <code>@action</code> decorators.</p> +<p>This router includes routes for the standard set of <code>list</code>, <code>create</code>, <code>retrieve</code>, <code>update</code>, <code>partial_update</code> and <code>destroy</code> actions.  The viewset can also mark additional methods to be routed, using the <code>@detail_route</code> or <code>@list_route</code> decorators.</p>  <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>  <p>By default the URLs created by <code>SimpleRouter</code> are appended with a trailing slash. @@ -280,6 +285,11 @@ This behavior can be modified by setting the <code>trailing_slash</code> argumen  <pre class="prettyprint lang-py"><code>router = SimpleRouter(trailing_slash=False)  </code></pre>  <p>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.</p> +<p>The router will match lookup values containing any characters except slashes and period characters.  For a more restrictive (or lenient) lookup pattern, set the <code>lookup_value_regex</code> attribute on the viewset.  For example, you can limit the lookup to valid UUIDs:</p> +<pre class="prettyprint lang-py"><code>class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): +    lookup_field = 'my_model_id' +    lookup_value_regex = '[0-9a-f]{32}' +</code></pre>  <h2 id="defaultrouter">DefaultRouter</h2>  <p>This router is similar to <code>SimpleRouter</code> 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 <code>.json</code> style format suffixes.</p>  <table border=1> @@ -287,12 +297,12 @@ This behavior can be modified by setting the <code>trailing_slash</code> argumen      <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>  <p>As with <code>SimpleRouter</code> the trailing slashes on the URL routes can be removed by setting the <code>trailing_slash</code> argument to <code>False</code> when instantiating the router.</p> @@ -314,26 +324,75 @@ This behavior can be modified by setting the <code>trailing_slash</code> argumen  <li><code>{basename}</code> - The base to use for the URL names that are created.</li>  </ul>  <p><strong>initkwargs</strong>: A dictionary of any additional arguments that should be passed when instantiating the view.  Note that the <code>suffix</code> argument is reserved for identifying the viewset type, used when generating the view name and breadcrumb links.</p> +<h2 id="customizing-dynamic-routes">Customizing dynamic routes</h2> +<p>You can also customize how the <code>@list_route</code> and <code>@detail_route</code> decorators are routed. +To route either or both of these decorators, include a <code>DynamicListRoute</code> and/or <code>DynamicDetailRoute</code> named tuple in the <code>.routes</code> list.</p> +<p>The arguments to <code>DynamicListRoute</code> and <code>DynamicDetailRoute</code> are:</p> +<p><strong>url</strong>: A string representing the URL to be routed. May include the same format strings as <code>Route</code>, and additionally accepts the <code>{methodname}</code> and <code>{methodnamehyphen}</code> format strings.</p> +<p><strong>name</strong>: The name of the URL as used in <code>reverse</code> calls. May include the following format strings: <code>{basename}</code>, <code>{methodname}</code> and <code>{methodnamehyphen}</code>.</p> +<p><strong>initkwargs</strong>: A dictionary of any additional arguments that should be passed when instantiating the view.</p>  <h2 id="example">Example</h2>  <p>The following example will only route to the <code>list</code> and <code>retrieve</code> actions, and does not use the trailing slash convention.</p> -<pre class="prettyprint lang-py"><code>from rest_framework.routers import Route, SimpleRouter +<pre class="prettyprint lang-py"><code>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={} +        )      ]  </code></pre> -<p>The <code>SimpleRouter</code> class provides another example of setting the <code>.routes</code> attribute.</p> +<p>Let's take a look at the routes our <code>CustomReadOnlyRouter</code> would generate for a simple viewset.</p> +<p><code>views.py</code>:</p> +<pre class="prettyprint lang-py"><code>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]) +</code></pre> +<p><code>urls.py</code>:</p> +<pre class="prettyprint lang-py"><code>router = CustomReadOnlyRouter() +router.register('users', UserViewSet) +urlpatterns = router.urls +</code></pre> +<p>The following mappings would be generated...</p> +<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> + +<p>For another example of setting the <code>.routes</code> attribute, see the source code for the <code>SimpleRouter</code> class.</p>  <h2 id="advanced-custom-routers">Advanced custom routers</h2>  <p>If you want to provide totally custom behavior, you can override <code>BaseRouter</code> and override the <code>get_urls(self)</code> method.  The method should inspect the registered viewsets and return a list of URL patterns.  The registered prefix, viewset and basename tuples may be inspected by accessing the <code>self.registry</code> attribute.  </p>  <p>You may also want to override the <code>get_default_base_name(self, viewset)</code> method, or else always explicitly set the <code>base_name</code> argument when registering your viewsets with the router.</p> diff --git a/api-guide/serializers.html b/api-guide/serializers.html index 850b6dc5..f90aff16 100644 --- a/api-guide/serializers.html +++ b/api-guide/serializers.html @@ -209,6 +209,7 @@ a.fusion-poweredby {  <li class="main"><a href="#third-party-packages">Third party packages</a></li>  <li><a href="#mongoenginemodelserializer">MongoengineModelSerializer</a></li>  <li><a href="#geofeaturemodelserializer">GeoFeatureModelSerializer</a></li> +<li><a href="#hstoreserializer">HStoreSerializer</a></li>                <div class="promo"> @@ -672,6 +673,8 @@ The <code>ModelSerializer</code> class lets you automatically create a Serialize  <p>The <a href="https://github.com/umutbozkurt/django-rest-framework-mongoengine">django-rest-framework-mongoengine</a> package provides a <code>MongoEngineModelSerializer</code> serializer class that supports using MongoDB as the storage layer for Django REST framework.</p>  <h2 id="geofeaturemodelserializer">GeoFeatureModelSerializer</h2>  <p>The <a href="https://github.com/djangonauts/django-rest-framework-gis">django-rest-framework-gis</a> package provides a <code>GeoFeatureModelSerializer</code> serializer class that supports GeoJSON both for read and write operations.</p> +<h2 id="hstoreserializer">HStoreSerializer</h2> +<p>The <a href="https://github.com/djangonauts/django-rest-framework-hstore">django-rest-framework-hstore</a> package provides an <code>HStoreSerializer</code> to support <a href="https://github.com/djangonauts/django-hstore">django-hstore</a> <code>DictionaryField</code> model field and its <code>schema-mode</code> feature.</p>            </div><!--/span-->          </div><!--/row-->        </div><!--/.fluid-container--> diff --git a/api-guide/settings.html b/api-guide/settings.html index 880b3249..59823263 100644 --- a/api-guide/settings.html +++ b/api-guide/settings.html @@ -434,6 +434,9 @@ If set to <code>None</code> then generic filtering is disabled.</p>  <h4 id="format_suffix_kwarg">FORMAT_SUFFIX_KWARG</h4>  <p>The name of a parameter in the URL conf that may be used to provide a format suffix.</p>  <p>Default: <code>'format'</code></p> +<h4 id="num_proxies">NUM_PROXIES</h4> +<p>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 <code>None</code> then less strict IP matching will be used by the throttle classes.</p> +<p>Default: <code>None</code></p>            </div><!--/span-->          </div><!--/row-->        </div><!--/.fluid-container--> diff --git a/api-guide/throttling.html b/api-guide/throttling.html index e0bb189c..49642481 100644 --- a/api-guide/throttling.html +++ b/api-guide/throttling.html @@ -229,7 +229,7 @@ If any throttle check fails an <code>exceptions.Throttled</code> exception will      'DEFAULT_THROTTLE_RATES': {          'anon': '100/day',          'user': '1000/day' -    }         +    }  }  </code></pre>  <p>The rate descriptions used in <code>DEFAULT_THROTTLE_RATES</code> may include <code>second</code>, <code>minute</code>, <code>hour</code> or <code>day</code> as the throttle period.</p> @@ -257,6 +257,11 @@ def example_view(request, format=None):      }      return Response(content)  </code></pre> +<h2 id="how-clients-are-identified">How clients are identified</h2> +<p>The <code>X-Forwarded-For</code> and <code>Remote-Addr</code> HTTP headers are used to uniquely identify client IP addresses for throttling.  If the <code>X-Forwarded-For</code> header is present then it will be used, otherwise the value of the <code>Remote-Addr</code> header will be used.</p> +<p>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 <code>NUM_PROXIES</code> 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 <code>X-Forwarded-For</code> header, once any application proxy IP addresses have first been excluded.  If set to zero, then the <code>Remote-Addr</code> header will always be used as the identifying IP address.</p> +<p>It is important to understand that if you configure the <code>NUM_PROXIES</code> setting, then all clients behind a unique <a href="http://en.wikipedia.org/wiki/Network_address_translation">NAT'd</a> gateway will be treated as a single client.</p> +<p>Further context on how the <code>X-Forwarded-For</code> header works, and identifing a remote client IP can be <a href="http://oxpedia.org/wiki/index.php?title=AppSuite:Grizzly#Multiple_Proxies_in_front_of_the_cluster">found here</a>.</p>  <h2 id="setting-up-the-cache">Setting up the cache</h2>  <p>The throttle classes provided by REST framework use Django's cache backend.  You should make sure that you've set appropriate <a href="https://docs.djangoproject.com/en/dev/ref/settings/#caches">cache settings</a>.  The default value of <code>LocMemCache</code> backend should be okay for simple setups.  See Django's <a href="https://docs.djangoproject.com/en/dev/topics/cache/#setting-up-the-cache">cache documentation</a> for more details.</p>  <p>If you need to use a cache other than <code>'default'</code>, you can do so by creating a custom throttle class and setting the <code>cache</code> attribute.  For example:</p> diff --git a/api-guide/viewsets.html b/api-guide/viewsets.html index b154144e..454d7d82 100644 --- a/api-guide/viewsets.html +++ b/api-guide/viewsets.html @@ -186,7 +186,7 @@ a.fusion-poweredby {                <ul class="nav nav-list side-nav well sidebar-nav-fixed">                  <li class="main"><a href="#viewsets">ViewSets</a></li>  <li><a href="#example">Example</a></li> -<li><a href="#marking-extra-methods-for-routing">Marking extra methods for routing</a></li> +<li><a href="#marking-extra-actions-for-routing">Marking extra actions for routing</a></li>  <li class="main"><a href="#api-reference">API Reference</a></li>  <li><a href="#viewset">ViewSet</a></li>  <li><a href="#genericviewset">GenericViewSet</a></li> @@ -263,7 +263,7 @@ urlpatterns = router.urls  <li>By using routers, we no longer need to deal with wiring up the URL conf ourselves.</li>  </ul>  <p>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.</p> -<h2 id="marking-extra-methods-for-routing">Marking extra methods for routing</h2> +<h2 id="marking-extra-actions-for-routing">Marking extra actions for routing</h2>  <p>The default routers included with REST framework will provide routes for a standard set of create/retrieve/update/destroy style operations, as shown below:</p>  <pre class="prettyprint lang-py"><code>class UserViewSet(viewsets.ViewSet):      """ @@ -292,12 +292,13 @@ urlpatterns = router.urls      def destroy(self, request, pk=None):          pass  </code></pre> -<p>If you have ad-hoc methods that you need to be routed to, you can mark them as requiring routing using the <code>@link</code> or <code>@action</code> decorators.  The <code>@link</code> decorator will route <code>GET</code> requests, and the <code>@action</code> decorator will route <code>POST</code> requests.</p> +<p>If you have ad-hoc methods that you need to be routed to, you can mark them as requiring routing using the <code>@detail_route</code> or <code>@list_route</code> decorators.</p> +<p>The <code>@detail_route</code> decorator contains <code>pk</code> in its URL pattern and is intended for methods which require a single instance. The <code>@list_route</code> decorator is intended for methods which operate on a list of objects.</p>  <p>For example:</p>  <pre class="prettyprint lang-py"><code>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 @@ -308,7 +309,7 @@ class UserViewSet(viewsets.ModelViewSet):      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) @@ -319,14 +320,21 @@ class UserViewSet(viewsets.ModelViewSet):          else:              return Response(serializer.errors,                              status=status.HTTP_400_BAD_REQUEST) + +    @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)  </code></pre> -<p>The <code>@action</code> and <code>@link</code> decorators can additionally take extra arguments that will be set for the routed view only.  For example...</p> -<pre class="prettyprint lang-py"><code>    @action(permission_classes=[IsAdminOrIsSelf]) +<p>The decorators can additionally take extra arguments that will be set for the routed view only.  For example...</p> +<pre class="prettyprint lang-py"><code>    @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf])      def set_password(self, request, pk=None):         ...  </code></pre> -<p>The <code>@action</code> decorator will route <code>POST</code> requests by default, but may also accept other HTTP methods, by using the <code>methods</code> argument.  For example:</p> -<pre class="prettyprint lang-py"><code>    @action(methods=['POST', 'DELETE']) +<p>Theses decorators will route <code>GET</code> requests by default, but may also accept other HTTP methods, by using the <code>methods</code> argument.  For example:</p> +<pre class="prettyprint lang-py"><code>    @detail_route(methods=['post', 'delete'])      def unset_password(self, request, pk=None):         ...  </code></pre> | 
