Deployed fc588f53 with MkDocs version: 0.16.3

This commit is contained in:
Carlton Gibson 2018-04-03 14:37:24 +01:00
parent 7931ed8d5b
commit 6fdeed2e2c
26 changed files with 504 additions and 226 deletions

View File

@ -660,9 +660,34 @@ urlpatterns += [
<p>The <code>obtain_auth_token</code> view will return a JSON response when valid <code>username</code> and <code>password</code> fields are POSTed to the view using form data or JSON:</p> <p>The <code>obtain_auth_token</code> view will return a JSON response when valid <code>username</code> and <code>password</code> fields are POSTed to the view using form data or JSON:</p>
<pre><code>{ 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' } <pre><code>{ 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' }
</code></pre> </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> <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.</p>
<p>By default there are no permissions or throttling applied to the <code>obtain_auth_token</code> view. If you do wish to apply throttling you'll need to override the view class, <p>By default there are no permissions or throttling applied to the <code>obtain_auth_token</code> view. If you do wish to apply throttling you'll need to override the view class,
and include them using the <code>throttle_classes</code> attribute.</p> and include them using the <code>throttle_classes</code> attribute.</p>
<p>If you need a customized version of the <code>obtain_auth_token</code> view, you can do so by subclassing the <code>ObtainAuthToken</code> view class, and using that in your url conf instead.</p>
<p>For example, you may return additional user information beyond the <code>token</code> value:</p>
<pre><code>from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
class CustomAuthToken(ObtainAuthToken):
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data,
context={'request': request})
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
return Response({
'token': token.key,
'user_id': user.pk,
'email': user.email
})
</code></pre>
<p>And in your <code>urls.py</code>:</p>
<pre><code>urlpatterns += [
url(r'^api-token-auth/', CustomAuthToken.as_view())
]
</code></pre>
<h5 id="with-django-admin"><a class="toclink" href="#with-django-admin">With Django admin</a></h5> <h5 id="with-django-admin"><a class="toclink" href="#with-django-admin">With Django admin</a></h5>
<p>It is also possible to create Tokens manually through admin interface. In case you are using a large user base, we recommend that you monkey patch the <code>TokenAdmin</code> class to customize it to your needs, more specifically by declaring the <code>user</code> field as <code>raw_field</code>.</p> <p>It is also possible to create Tokens manually through admin interface. In case you are using a large user base, we recommend that you monkey patch the <code>TokenAdmin</code> class to customize it to your needs, more specifically by declaring the <code>user</code> field as <code>raw_field</code>.</p>
<p><code>your_app/admin.py</code>:</p> <p><code>your_app/admin.py</code>:</p>

View File

@ -445,6 +445,20 @@
</li> </li>
<li class="main">
<a href="#generic-error-views">Generic Error Views</a>
</li>
<li>
<a href="#rest_frameworkexceptionsserver_error">rest_framework.exceptions.server_error</a>
</li>
<li>
<a href="#rest_frameworkexceptionsserver_error_1">rest_framework.exceptions.server_error</a>
</li>
<div class="promo"> <div class="promo">
<hr/> <hr/>
@ -625,6 +639,22 @@ dictionary of items:</p>
</code></pre> </code></pre>
<p>The generic views use the <code>raise_exception=True</code> flag, which means that you can override the style of validation error responses globally in your API. To do so, use a custom exception handler, as described above.</p> <p>The generic views use the <code>raise_exception=True</code> flag, which means that you can override the style of validation error responses globally in your API. To do so, use a custom exception handler, as described above.</p>
<p>By default this exception results in a response with the HTTP status code "400 Bad Request".</p> <p>By default this exception results in a response with the HTTP status code "400 Bad Request".</p>
<hr />
<h1 id="generic-error-views"><a class="toclink" href="#generic-error-views">Generic Error Views</a></h1>
<p>Django REST Framework provides two error views suitable for providing generic JSON <code>500</code> Server Error and
<code>400</code> Bad Request responses. (Django's default error views provide HTML responses, which may not be appropriate for an
API-only application.)</p>
<p>Use these as per <a href="https://docs.djangoproject.com/en/dev/topics/http/views/#customizing-error-views">Django's Customizing error views documentation</a>.</p>
<h2 id="rest_frameworkexceptionsserver_error"><a class="toclink" href="#rest_frameworkexceptionsserver_error"><code>rest_framework.exceptions.server_error</code></a></h2>
<p>Returns a response with status code <code>500</code> and <code>application/json</code> content type.</p>
<p>Set as <code>handler500</code>:</p>
<pre><code>handler500 = 'rest_framework.exceptions.server_error'
</code></pre>
<h2 id="rest_frameworkexceptionsserver_error_1"><a class="toclink" href="#rest_frameworkexceptionsserver_error_1"><code>rest_framework.exceptions.server_error</code></a></h2>
<p>Returns a response with status code <code>400</code> and <code>application/json</code> content type.</p>
<p>Set as <code>handler400</code>:</p>
<pre><code>handler400 = 'rest_framework.exceptions.bad_request'
</code></pre>
</div> <!--/span--> </div> <!--/span-->

View File

@ -528,6 +528,10 @@
<a href="#dictfield">DictField</a> <a href="#dictfield">DictField</a>
</li> </li>
<li>
<a href="#hstorefield">HStoreField</a>
</li>
<li> <li>
<a href="#jsonfield">JSONField</a> <a href="#jsonfield">JSONField</a>
</li> </li>
@ -579,7 +583,7 @@
</li> </li>
<li> <li>
<a href="#djangrestframework-recursive">djangrestframework-recursive</a> <a href="#djangorestframework-recursive">djangorestframework-recursive</a>
</li> </li>
<li> <li>
@ -634,16 +638,16 @@
Set to false if this field is not required to be present during deserialization.</p> Set to false if this field is not required to be present during deserialization.</p>
<p>Setting this to <code>False</code> also allows the object attribute or dictionary key to be omitted from output when serializing the instance. If the key is not present it will simply not be included in the output representation.</p> <p>Setting this to <code>False</code> also allows the object attribute or dictionary key to be omitted from output when serializing the instance. If the key is not present it will simply not be included in the output representation.</p>
<p>Defaults to <code>True</code>.</p> <p>Defaults to <code>True</code>.</p>
<h3 id="allow_null"><a class="toclink" href="#allow_null"><code>allow_null</code></a></h3>
<p>Normally an error will be raised if <code>None</code> is passed to a serializer field. Set this keyword argument to <code>True</code> if <code>None</code> should be considered a valid value.</p>
<p>Note that setting this argument to <code>True</code> will imply a default value of <code>null</code> for serialization output, but does not imply a default for input deserialization.</p>
<p>Defaults to <code>False</code></p>
<h3 id="default"><a class="toclink" href="#default"><code>default</code></a></h3> <h3 id="default"><a class="toclink" href="#default"><code>default</code></a></h3>
<p>If set, this gives the default value that will be used for the field if no input value is supplied. If not set the default behaviour is to not populate the attribute at all.</p> <p>If set, this gives the default value that will be used for the field if no input value is supplied. If not set the default behaviour is to not populate the attribute at all.</p>
<p>The <code>default</code> is not applied during partial update operations. In the partial update case only fields that are provided in the incoming data will have a validated value returned.</p> <p>The <code>default</code> is not applied during partial update operations. In the partial update case only fields that are provided in the incoming data will have a validated value returned.</p>
<p>May be set to a function or other callable, in which case the value will be evaluated each time it is used. When called, it will receive no arguments. If the callable has a <code>set_context</code> method, that will be called each time before getting the value with the field instance as only argument. This works the same way as for <a href="../validators/#using-set_context">validators</a>.</p> <p>May be set to a function or other callable, in which case the value will be evaluated each time it is used. When called, it will receive no arguments. If the callable has a <code>set_context</code> method, that will be called each time before getting the value with the field instance as only argument. This works the same way as for <a href="../validators/#using-set_context">validators</a>.</p>
<p>When serializing the instance, default will be used if the the object attribute or dictionary key is not present in the instance.</p> <p>When serializing the instance, default will be used if the the object attribute or dictionary key is not present in the instance.</p>
<p>Note that setting a <code>default</code> value implies that the field is not required. Including both the <code>default</code> and <code>required</code> keyword arguments is invalid and will raise an error.</p> <p>Note that setting a <code>default</code> value implies that the field is not required. Including both the <code>default</code> and <code>required</code> keyword arguments is invalid and will raise an error.</p>
<h3 id="allow_null"><a class="toclink" href="#allow_null"><code>allow_null</code></a></h3>
<p>Normally an error will be raised if <code>None</code> is passed to a serializer field. Set this keyword argument to <code>True</code> if <code>None</code> should be considered a valid value.</p>
<p>Note that, without an explicit <code>default</code>, setting this argument to <code>True</code> will imply a <code>default</code> value of <code>null</code> for serialization output, but does not imply a default for input deserialization.</p>
<p>Defaults to <code>False</code></p>
<h3 id="source"><a class="toclink" href="#source"><code>source</code></a></h3> <h3 id="source"><a class="toclink" href="#source"><code>source</code></a></h3>
<p>The name of the attribute that will be used to populate the field. May be a method that only takes a <code>self</code> argument, such as <code>URLField(source='get_absolute_url')</code>, or may use dotted notation to traverse attributes, such as <code>EmailField(source='user.email')</code>. When serializing fields with dotted notation, it may be necessary to provide a <code>default</code> value if any object is not present or is empty during attribute traversal.</p> <p>The name of the attribute that will be used to populate the field. May be a method that only takes a <code>self</code> argument, such as <code>URLField(source='get_absolute_url')</code>, or may use dotted notation to traverse attributes, such as <code>EmailField(source='user.email')</code>. When serializing fields with dotted notation, it may be necessary to provide a <code>default</code> value if any object is not present or is empty during attribute traversal.</p>
<p>The value <code>source='*'</code> has a special meaning, and is used to indicate that the entire object should be passed through to the field. This can be useful for creating nested representations, or for fields which require access to the complete object in order to determine the output representation.</p> <p>The value <code>source='*'</code> has a special meaning, and is used to indicate that the entire object should be passed through to the field. This can be useful for creating nested representations, or for fields which require access to the complete object in order to determine the output representation.</p>
@ -924,6 +928,13 @@ Django's regular <a href="https://docs.djangoproject.com/en/stable/ref/settings/
<pre><code>class DocumentField(DictField): <pre><code>class DocumentField(DictField):
child = CharField() child = CharField()
</code></pre> </code></pre>
<h2 id="hstorefield"><a class="toclink" href="#hstorefield">HStoreField</a></h2>
<p>A preconfigured <code>DictField</code> that is compatible with Django's postgres <code>HStoreField</code>.</p>
<p><strong>Signature</strong>: <code>HStoreField(child=&lt;A_FIELD_INSTANCE&gt;)</code></p>
<ul>
<li><code>child</code> - A field instance that is used for validating the values in the dictionary. The default child field accepts both empty strings and null values.</li>
</ul>
<p>Note that the child field <strong>must</strong> be an instance of <code>CharField</code>, as the hstore extension stores values as strings.</p>
<h2 id="jsonfield"><a class="toclink" href="#jsonfield">JSONField</a></h2> <h2 id="jsonfield"><a class="toclink" href="#jsonfield">JSONField</a></h2>
<p>A field class that validates that the incoming data structure consists of valid JSON primitives. In its alternate binary mode, it will represent and validate JSON-encoded binary strings.</p> <p>A field class that validates that the incoming data structure consists of valid JSON primitives. In its alternate binary mode, it will represent and validate JSON-encoded binary strings.</p>
<p><strong>Signature</strong>: <code>JSONField(binary)</code></p> <p><strong>Signature</strong>: <code>JSONField(binary)</code></p>
@ -1189,7 +1200,7 @@ or overly complex.</p>
<p>The <a href="https://drf-compound-fields.readthedocs.io">drf-compound-fields</a> package provides "compound" serializer fields, such as lists of simple values, which can be described by other fields rather than serializers with the <code>many=True</code> option. Also provided are fields for typed dictionaries and values that can be either a specific type or a list of items of that type.</p> <p>The <a href="https://drf-compound-fields.readthedocs.io">drf-compound-fields</a> package provides "compound" serializer fields, such as lists of simple values, which can be described by other fields rather than serializers with the <code>many=True</code> option. Also provided are fields for typed dictionaries and values that can be either a specific type or a list of items of that type.</p>
<h2 id="drf-extra-fields"><a class="toclink" href="#drf-extra-fields">DRF Extra Fields</a></h2> <h2 id="drf-extra-fields"><a class="toclink" href="#drf-extra-fields">DRF Extra Fields</a></h2>
<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> <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="djangrestframework-recursive"><a class="toclink" href="#djangrestframework-recursive">djangrestframework-recursive</a></h2> <h2 id="djangorestframework-recursive"><a class="toclink" href="#djangorestframework-recursive">djangorestframework-recursive</a></h2>
<p>the <a href="https://github.com/heywbj/django-rest-framework-recursive">djangorestframework-recursive</a> package provides a <code>RecursiveField</code> for serializing and deserializing recursive structures</p> <p>the <a href="https://github.com/heywbj/django-rest-framework-recursive">djangorestframework-recursive</a> package provides a <code>RecursiveField</code> for serializing and deserializing recursive structures</p>
<h2 id="django-rest-framework-gis"><a class="toclink" href="#django-rest-framework-gis">django-rest-framework-gis</a></h2> <h2 id="django-rest-framework-gis"><a class="toclink" href="#django-rest-framework-gis">django-rest-framework-gis</a></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> <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>

View File

@ -491,7 +491,7 @@ Content-Type: application/json
<h2 id="creating-schema-endpoints"><a class="toclink" href="#creating-schema-endpoints">Creating schema endpoints</a></h2> <h2 id="creating-schema-endpoints"><a class="toclink" href="#creating-schema-endpoints">Creating schema endpoints</a></h2>
<p>If you have specific requirements for creating schema endpoints that are accessed with regular <code>GET</code> requests, you might consider re-using the metadata API for doing so.</p> <p>If you have specific requirements for creating schema endpoints that are accessed with regular <code>GET</code> requests, you might consider re-using the metadata API for doing so.</p>
<p>For example, the following additional route could be used on a viewset to provide a linkable schema endpoint.</p> <p>For example, the following additional route could be used on a viewset to provide a linkable schema endpoint.</p>
<pre><code>@list_route(methods=['GET']) <pre><code>@action(methods=['GET'], detail=False)
def schema(self, request): def schema(self, request):
meta = self.metadata_class() meta = self.metadata_class()
data = meta.determine_metadata(request, self) data = meta.determine_metadata(request, self)

View File

@ -468,6 +468,10 @@
<a href="#django-rest-framework-api-key">Django Rest Framework API Key</a> <a href="#django-rest-framework-api-key">Django Rest Framework API Key</a>
</li> </li>
<li>
<a href="#django-rest-framework-role-filters">Django Rest Framework Role Filters</a>
</li>
<div class="promo"> <div class="promo">
@ -680,6 +684,8 @@ class BlacklistPermission(permissions.BasePermission):
<p>The <a href="https://github.com/computer-lab/django-rest-framework-roles">Django Rest Framework Roles</a> package makes it easier to parameterize your API over multiple types of users.</p> <p>The <a href="https://github.com/computer-lab/django-rest-framework-roles">Django Rest Framework Roles</a> package makes it easier to parameterize your API over multiple types of users.</p>
<h2 id="django-rest-framework-api-key"><a class="toclink" href="#django-rest-framework-api-key">Django Rest Framework API Key</a></h2> <h2 id="django-rest-framework-api-key"><a class="toclink" href="#django-rest-framework-api-key">Django Rest Framework API Key</a></h2>
<p>The <a href="https://github.com/manosim/django-rest-framework-api-key">Django Rest Framework API Key</a> package allows you to ensure that every request made to the server requires an API key header. You can generate one from the django admin interface.</p> <p>The <a href="https://github.com/manosim/django-rest-framework-api-key">Django Rest Framework API Key</a> package allows you to ensure that every request made to the server requires an API key header. You can generate one from the django admin interface.</p>
<h2 id="django-rest-framework-role-filters"><a class="toclink" href="#django-rest-framework-role-filters">Django Rest Framework Role Filters</a></h2>
<p>The <a href="https://github.com/allisson/django-rest-framework-role-filters">Django Rest Framework Role Filters</a> package provides simple filtering over multiple types of roles.</p>
</div> <!--/span--> </div> <!--/span-->

View File

@ -519,77 +519,75 @@ urlpatterns += router.urls
url(r'^', include(router.urls)), url(r'^', include(router.urls)),
] ]
</code></pre> </code></pre>
<p>Router URL patterns can also be namespaces.</p> <p>You may use <code>include</code> with an application namespace:</p>
<pre><code>urlpatterns = [ <pre><code>urlpatterns = [
url(r'^forgot-password/$', ForgotPasswordFormView.as_view()), url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
url(r'^api/', include(router.urls, namespace='api')), url(r'^api/', include((router.urls, 'app_name'))),
] ]
</code></pre> </code></pre>
<p>If using namespacing with hyperlinked serializers you'll also need to ensure that any <code>view_name</code> parameters on the serializers correctly reflect the namespace. In the example above you'd need to include a parameter such as <code>view_name='api:user-detail'</code> for serializer fields hyperlinked to the user detail view.</p> <p>Or both an application and instance namespace:</p>
<h3 id="extra-link-and-actions"><a class="toclink" href="#extra-link-and-actions">Extra link and actions</a></h3> <pre><code>urlpatterns = [
<p>Any methods on the viewset decorated with <code>@detail_route</code> or <code>@list_route</code> will also be routed. url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
For example, given a method like this on the <code>UserViewSet</code> class:</p> url(r'^api/', include((router.urls, 'app_name'), namespace='instance_name')),
]
</code></pre>
<p>See Django's <a href="https://docs.djangoproject.com/en/1.11/topics/http/urls/#url-namespaces">URL namespaces docs</a> and the <a href="https://docs.djangoproject.com/en/2.0/ref/urls/#include"><code>include</code> API reference</a> for more details.</p>
<hr />
<p><strong>Note</strong>: If using namespacing with hyperlinked serializers you'll also need to ensure that any <code>view_name</code> parameters
on the serializers correctly reflect the namespace. In the examples above you'd need to include a parameter such as
<code>view_name='app_name:user-detail'</code> for serializer fields hyperlinked to the user detail view.</p>
<p>The automatic <code>view_name</code> generation uses a pattern like <code>%(model_name)-detail</code>. Unless your models names actually clash
you may be better off <strong>not</strong> namespacing your Django REST Framework views when using hyperlinked serializers.</p>
<hr />
<h3 id="routing-for-extra-actions"><a class="toclink" href="#routing-for-extra-actions">Routing for extra actions</a></h3>
<p>A viewset may <a href="../viewsets/#marking-extra-actions-for-routing">mark extra actions for routing</a> by decorating a method with the <code>@action</code> decorator. These extra actions will be included in the generated routes. For example, given the <code>set_password</code> method on the <code>UserViewSet</code> class:</p>
<pre><code>from myapp.permissions import IsAdminOrIsSelf <pre><code>from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import detail_route from rest_framework.decorators import action
class UserViewSet(ModelViewSet): class UserViewSet(ModelViewSet):
... ...
@detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf]) @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf])
def set_password(self, request, pk=None): def set_password(self, request, pk=None):
... ...
</code></pre> </code></pre>
<p>The following URL pattern would additionally be generated:</p> <p>The following route would be generated:</p>
<ul> <ul>
<li>URL pattern: <code>^users/{pk}/set_password/$</code> Name: <code>'user-set-password'</code></li> <li>URL pattern: <code>^users/{pk}/set_password/$</code></li>
<li>URL name: <code>'user-set-password'</code></li>
</ul> </ul>
<p>If you do not want to use the default URL generated for your custom action, you can instead use the url_path parameter to customize it.</p> <p>By default, the URL pattern is based on the method name, and the URL name is the combination of the <code>ViewSet.basename</code> and the hyphenated method name.
If you don't want to use the defaults for either of these values, you can instead provide the <code>url_path</code> and <code>url_name</code> arguments to the <code>@action</code> decorator.</p>
<p>For example, if you want to change the URL for our custom action to <code>^users/{pk}/change-password/$</code>, you could write:</p> <p>For example, if you want to change the URL for our custom action to <code>^users/{pk}/change-password/$</code>, you could write:</p>
<pre><code>from myapp.permissions import IsAdminOrIsSelf <pre><code>from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import detail_route from rest_framework.decorators import action
class UserViewSet(ModelViewSet): class UserViewSet(ModelViewSet):
... ...
@detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf], url_path='change-password') @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf],
url_path='change-password', url_name='change_password')
def set_password(self, request, pk=None): def set_password(self, request, pk=None):
... ...
</code></pre> </code></pre>
<p>The above example would now generate the following URL pattern:</p> <p>The above example would now generate the following URL pattern:</p>
<ul> <ul>
<li>URL pattern: <code>^users/{pk}/change-password/$</code> Name: <code>'user-change-password'</code></li> <li>URL path: <code>^users/{pk}/change-password/$</code></li>
<li>URL name: <code>'user-change_password'</code></li>
</ul> </ul>
<p>In the case you do not want to use the default name generated for your custom action, you can use the url_name parameter to customize it.</p>
<p>For example, if you want to change the name of our custom action to <code>'user-change-password'</code>, you could write:</p>
<pre><code>from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import detail_route
class UserViewSet(ModelViewSet):
...
@detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf], url_name='change-password')
def set_password(self, request, pk=None):
...
</code></pre>
<p>The above example would now generate the following URL pattern:</p>
<ul>
<li>URL pattern: <code>^users/{pk}/set_password/$</code> Name: <code>'user-change-password'</code></li>
</ul>
<p>You can also use url_path and url_name parameters together to obtain extra control on URL generation for custom views.</p>
<p>For more information see the viewset documentation on <a href="../viewsets/#marking-extra-actions-for-routing">marking extra actions for routing</a>.</p>
<h1 id="api-guide"><a class="toclink" href="#api-guide">API Guide</a></h1> <h1 id="api-guide"><a class="toclink" href="#api-guide">API Guide</a></h1>
<h2 id="simplerouter"><a class="toclink" href="#simplerouter">SimpleRouter</a></h2> <h2 id="simplerouter"><a class="toclink" href="#simplerouter">SimpleRouter</a></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>@detail_route</code> or <code>@list_route</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>@action</code> decorator.</p>
<table border=1> <table border=1>
<tr><th>URL Style</th><th>HTTP Method</th><th>Action</th><th>URL Name</th></tr> <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 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>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>{prefix}/{url_path}/</td><td>GET, or as specified by `methods` argument</td><td>`@action(detail=False)` decorated method</td><td>{basename}-{url_name}</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 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>PUT</td><td>update</td></tr>
<tr><td>PATCH</td><td>partial_update</td></tr> <tr><td>PATCH</td><td>partial_update</td></tr>
<tr><td>DELETE</td><td>destroy</td></tr> <tr><td>DELETE</td><td>destroy</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> <tr><td>{prefix}/{lookup}/{url_path}/</td><td>GET, or as specified by `methods` argument</td><td>`@action(detail=True)` decorated method</td><td>{basename}-{url_name}</td></tr>
</table> </table>
<p>By default the URLs created by <code>SimpleRouter</code> are appended with a trailing slash. <p>By default the URLs created by <code>SimpleRouter</code> are appended with a trailing slash.
@ -609,12 +607,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>[.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 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>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>{prefix}/{url_path}/[.format]</td><td>GET, or as specified by `methods` argument</td><td>`@action(detail=False)` decorated method</td><td>{basename}-{url_name}</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 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>PUT</td><td>update</td></tr>
<tr><td>PATCH</td><td>partial_update</td></tr> <tr><td>PATCH</td><td>partial_update</td></tr>
<tr><td>DELETE</td><td>destroy</td></tr> <tr><td>DELETE</td><td>destroy</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> <tr><td>{prefix}/{lookup}/{url_path}/[.format]</td><td>GET, or as specified by `methods` argument</td><td>`@action(detail=True)` decorated method</td><td>{basename}-{url_name}</td></tr>
</table> </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> <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>
@ -635,17 +633,19 @@ This behavior can be modified by setting the <code>trailing_slash</code> argumen
<ul> <ul>
<li><code>{basename}</code> - The base to use for the URL names that are created.</li> <li><code>{basename}</code> - The base to use for the URL names that are created.</li>
</ul> </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> <p><strong>initkwargs</strong>: A dictionary of any additional arguments that should be passed when instantiating the view. Note that the <code>detail</code>, <code>basename</code>, and <code>suffix</code> arguments are reserved for viewset introspection and are also used by the browsable API to generate the view name and breadcrumb links.</p>
<h2 id="customizing-dynamic-routes"><a class="toclink" href="#customizing-dynamic-routes">Customizing dynamic routes</a></h2> <h2 id="customizing-dynamic-routes"><a class="toclink" href="#customizing-dynamic-routes">Customizing dynamic routes</a></h2>
<p>You can also customize how the <code>@list_route</code> and <code>@detail_route</code> decorators are routed. <p>You can also customize how the <code>@action</code> decorator is routed. Include the <code>DynamicRoute</code> named tuple in the <code>.routes</code> list, setting the <code>detail</code> argument as appropriate for the list-based and detail-based routes. In addition to <code>detail</code>, the arguments to <code>DynamicRoute</code> are:</p>
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><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>{url_path}</code> format string.</p>
<p>The arguments to <code>DynamicListRoute</code> and <code>DynamicDetailRoute</code> are:</p> <p><strong>name</strong>: The name of the URL as used in <code>reverse</code> calls. May include the following format strings:</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> <ul>
<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> <li><code>{basename}</code> - The base to use for the URL names that are created.</li>
<li><code>{url_name}</code> - The <code>url_name</code> provided to the <code>@action</code>.</li>
</ul>
<p><strong>initkwargs</strong>: A dictionary of any additional arguments that should be passed when instantiating the view.</p> <p><strong>initkwargs</strong>: A dictionary of any additional arguments that should be passed when instantiating the view.</p>
<h2 id="example"><a class="toclink" href="#example">Example</a></h2> <h2 id="example"><a class="toclink" href="#example">Example</a></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> <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><code>from rest_framework.routers import Route, DynamicDetailRoute, SimpleRouter <pre><code>from rest_framework.routers import Route, DynamicRoute, SimpleRouter
class CustomReadOnlyRouter(SimpleRouter): class CustomReadOnlyRouter(SimpleRouter):
""" """
@ -664,9 +664,10 @@ class CustomReadOnlyRouter(SimpleRouter):
name='{basename}-detail', name='{basename}-detail',
initkwargs={'suffix': 'Detail'} initkwargs={'suffix': 'Detail'}
), ),
DynamicDetailRoute( DynamicRoute(
url=r'^{prefix}/{lookup}/{methodnamehyphen}$', url=r'^{prefix}/{lookup}/{url_path}$',
name='{basename}-{methodnamehyphen}', name='{basename}-{url_name}',
detail=True,
initkwargs={} initkwargs={}
) )
] ]
@ -681,7 +682,7 @@ class CustomReadOnlyRouter(SimpleRouter):
serializer_class = UserSerializer serializer_class = UserSerializer
lookup_field = 'username' lookup_field = 'username'
@detail_route() @action(detail=True)
def group_names(self, request, pk=None): def group_names(self, request, pk=None):
""" """
Returns a list of all the group names that the given Returns a list of all the group names that the given

View File

@ -1014,7 +1014,7 @@ that do not expect a request body.</p>
if method=='POST': if method=='POST':
extra_fields = # ... list of extra fields for POST ... extra_fields = # ... list of extra fields for POST ...
manual_fields = super().get_manual_fields() manual_fields = super().get_manual_fields(path, method)
return manual_fields + extra_fields return manual_fields + extra_fields
</code></pre> </code></pre>
@ -1044,6 +1044,7 @@ plus an optional description.</p>
<p>The <code>ManualSchema</code> constructor takes two arguments:</p> <p>The <code>ManualSchema</code> constructor takes two arguments:</p>
<p><strong><code>fields</code></strong>: A list of <code>coreapi.Field</code> instances. Required.</p> <p><strong><code>fields</code></strong>: A list of <code>coreapi.Field</code> instances. Required.</p>
<p><strong><code>description</code></strong>: A string description. Optional.</p> <p><strong><code>description</code></strong>: A string description. Optional.</p>
<p><strong><code>encoding</code></strong>: Default <code>None</code>. A string encoding, e.g <code>application/json</code>. Optional.</p>
<hr /> <hr />
<h2 id="core-api"><a class="toclink" href="#core-api">Core API</a></h2> <h2 id="core-api"><a class="toclink" href="#core-api">Core API</a></h2>
<p>This documentation gives a brief overview of the components within the <code>coreapi</code> <p>This documentation gives a brief overview of the components within the <code>coreapi</code>

View File

@ -773,7 +773,7 @@ class BlogPostSerializer(serializers.Serializer):
<p><strong>Note:</strong> If your <code>&lt;field_name&gt;</code> is declared on your serializer with the parameter <code>required=False</code> then this validation step will not take place if the field is not included.</p> <p><strong>Note:</strong> If your <code>&lt;field_name&gt;</code> is declared on your serializer with the parameter <code>required=False</code> then this validation step will not take place if the field is not included.</p>
<hr /> <hr />
<h4 id="object-level-validation"><a class="toclink" href="#object-level-validation">Object-level validation</a></h4> <h4 id="object-level-validation"><a class="toclink" href="#object-level-validation">Object-level validation</a></h4>
<p>To do any other validation that requires access to multiple fields, add a method called <code>.validate()</code> to your <code>Serializer</code> subclass. This method takes a single argument, which is a dictionary of field values. It should raise a <code>ValidationError</code> if necessary, or just return the validated values. For example:</p> <p>To do any other validation that requires access to multiple fields, add a method called <code>.validate()</code> to your <code>Serializer</code> subclass. This method takes a single argument, which is a dictionary of field values. It should raise a <code>serializers.ValidationError</code> if necessary, or just return the validated values. For example:</p>
<pre><code>from rest_framework import serializers <pre><code>from rest_framework import serializers
class EventSerializer(serializers.Serializer): class EventSerializer(serializers.Serializer):
@ -1306,7 +1306,7 @@ def all_high_scores(request):
return Response(serializer.data) return Response(serializer.data)
</code></pre> </code></pre>
<h5 id="read-write-baseserializer-classes"><a class="toclink" href="#read-write-baseserializer-classes">Read-write <code>BaseSerializer</code> classes</a></h5> <h5 id="read-write-baseserializer-classes"><a class="toclink" href="#read-write-baseserializer-classes">Read-write <code>BaseSerializer</code> classes</a></h5>
<p>To create a read-write serializer we first need to implement a <code>.to_internal_value()</code> method. This method returns the validated values that will be used to construct the object instance, and may raise a <code>ValidationError</code> if the supplied data is in an incorrect format.</p> <p>To create a read-write serializer we first need to implement a <code>.to_internal_value()</code> method. This method returns the validated values that will be used to construct the object instance, and may raise a <code>serializers.ValidationError</code> if the supplied data is in an incorrect format.</p>
<p>Once you've implemented <code>.to_internal_value()</code>, the basic validation API will be available on the serializer, and you will be able to use <code>.is_valid()</code>, <code>.validated_data</code> and <code>.errors</code>.</p> <p>Once you've implemented <code>.to_internal_value()</code>, the basic validation API will be available on the serializer, and you will be able to use <code>.is_valid()</code>, <code>.validated_data</code> and <code>.errors</code>.</p>
<p>If you want to also support <code>.save()</code> you'll need to also implement either or both of the <code>.create()</code> and <code>.update()</code> methods.</p> <p>If you want to also support <code>.save()</code> you'll need to also implement either or both of the <code>.create()</code> and <code>.update()</code> methods.</p>
<p>Here's a complete example of our previous <code>HighScoreSerializer</code>, that's been updated to support both read and write operations.</p> <p>Here's a complete example of our previous <code>HighScoreSerializer</code>, that's been updated to support both read and write operations.</p>
@ -1317,15 +1317,15 @@ def all_high_scores(request):
# Perform the data validation. # Perform the data validation.
if not score: if not score:
raise ValidationError({ raise serializers.ValidationError({
'score': 'This field is required.' 'score': 'This field is required.'
}) })
if not player_name: if not player_name:
raise ValidationError({ raise serializers.ValidationError({
'player_name': 'This field is required.' 'player_name': 'This field is required.'
}) })
if len(player_name) &gt; 10: if len(player_name) &gt; 10:
raise ValidationError({ raise serializers.ValidationError({
'player_name': 'May not be more than 10 characters.' 'player_name': 'May not be more than 10 characters.'
}) })

View File

@ -562,7 +562,7 @@ If set to <code>None</code> then generic filtering is disabled.</p>
<hr /> <hr />
<h4 id="max_paginate_by"><a class="toclink" href="#max_paginate_by">MAX_PAGINATE_BY</a></h4> <h4 id="max_paginate_by"><a class="toclink" href="#max_paginate_by">MAX_PAGINATE_BY</a></h4>
<hr /> <hr />
<p><strong>This setting is pending deprecation.</strong></p> <p><strong>This setting has been removed.</strong></p>
<p>See the pagination documentation for further guidance on <a href="../pagination/#modifying-the-pagination-style">setting the pagination style</a>.</p> <p>See the pagination documentation for further guidance on <a href="../pagination/#modifying-the-pagination-style">setting the pagination style</a>.</p>
<hr /> <hr />
<h3 id="search_param"><a class="toclink" href="#search_param">SEARCH_PARAM</a></h3> <h3 id="search_param"><a class="toclink" href="#search_param">SEARCH_PARAM</a></h3>

View File

@ -454,7 +454,7 @@
<h1 id="throttling"><a class="toclink" href="#throttling">Throttling</a></h1> <h1 id="throttling"><a class="toclink" href="#throttling">Throttling</a></h1>
<blockquote> <blockquote>
<p>HTTP/1.1 420 Enhance Your Calm</p> <p>HTTP/1.1 420 Enhance Your Calm</p>
<p><a href="https://dev.twitter.com/docs/error-codes-responses">Twitter API rate limiting response</a></p> <p><a href="https://developer.twitter.com/en/docs/basics/rate-limiting">Twitter API rate limiting response</a></p>
</blockquote> </blockquote>
<p>Throttling is similar to <a href="../permissions/">permissions</a>, in that it determines if a request should be authorized. Throttles indicate a temporary state, and are used to control the rate of requests that clients can make to an API.</p> <p>Throttling is similar to <a href="../permissions/">permissions</a>, in that it determines if a request should be authorized. Throttles indicate a temporary state, and are used to control the rate of requests that clients can make to an API.</p>
<p>As with permissions, multiple throttles may be used. Your API might have a restrictive throttle for unauthenticated requests, and a less restrictive throttle for authenticated requests.</p> <p>As with permissions, multiple throttles may be used. Your API might have a restrictive throttle for unauthenticated requests, and a less restrictive throttle for authenticated requests.</p>

View File

@ -622,7 +622,6 @@ class ExampleSerializer(serializers.Serializer):
<p>A default class that can be used to <em>only set a default argument during create operations</em>. During updates the field is omitted.</p> <p>A default class that can be used to <em>only set a default argument during create operations</em>. During updates the field is omitted.</p>
<p>It takes a single argument, which is the default value or callable that should be used during create operations.</p> <p>It takes a single argument, which is the default value or callable that should be used during create operations.</p>
<pre><code>created_at = serializers.DateTimeField( <pre><code>created_at = serializers.DateTimeField(
read_only=True,
default=serializers.CreateOnlyDefault(timezone.now) default=serializers.CreateOnlyDefault(timezone.now)
) )
</code></pre> </code></pre>
@ -648,7 +647,7 @@ in the <code>.validate()</code> method, or else in the view.</p>
class Meta: class Meta:
fields = ('client', 'date', 'amount') fields = ('client', 'date', 'amount')
extra_kwargs = {'client': {'required': 'False'}} extra_kwargs = {'client': {'required': False}}
validators = [] # Remove a default "unique together" constraint. validators = [] # Remove a default "unique together" constraint.
</code></pre> </code></pre>
<h2 id="updating-nested-serializers"><a class="toclink" href="#updating-nested-serializers">Updating nested serializers</a></h2> <h2 id="updating-nested-serializers"><a class="toclink" href="#updating-nested-serializers">Updating nested serializers</a></h2>

View File

@ -477,7 +477,7 @@ reverse('bookings-list', request=request)
</code></pre> </code></pre>
<p>The above function will apply any URL transformations appropriate to the request version. For example:</p> <p>The above function will apply any URL transformations appropriate to the request version. For example:</p>
<ul> <ul>
<li>If <code>NamespacedVersioning</code> was being used, and the API version was 'v1', then the URL lookup used would be <code>'v1:bookings-list'</code>, which might resolve to a URL like <code>http://example.org/v1/bookings/</code>.</li> <li>If <code>NamespaceVersioning</code> was being used, and the API version was 'v1', then the URL lookup used would be <code>'v1:bookings-list'</code>, which might resolve to a URL like <code>http://example.org/v1/bookings/</code>.</li>
<li>If <code>QueryParameterVersioning</code> was being used, and the API version was <code>1.0</code>, then the returned URL might be something like <code>http://example.org/bookings/?version=1.0</code></li> <li>If <code>QueryParameterVersioning</code> was being used, and the API version was <code>1.0</code>, then the returned URL might be something like <code>http://example.org/bookings/?version=1.0</code></li>
</ul> </ul>
<h4 id="versioned-apis-and-hyperlinked-serializers"><a class="toclink" href="#versioned-apis-and-hyperlinked-serializers">Versioned APIs and hyperlinked serializers</a></h4> <h4 id="versioned-apis-and-hyperlinked-serializers"><a class="toclink" href="#versioned-apis-and-hyperlinked-serializers">Versioned APIs and hyperlinked serializers</a></h4>

View File

@ -394,6 +394,10 @@
<a href="#viewset-actions">ViewSet actions</a> <a href="#viewset-actions">ViewSet actions</a>
</li> </li>
<li>
<a href="#introspecting-viewset-actions">Introspecting ViewSet actions</a>
</li>
<li> <li>
<a href="#marking-extra-actions-for-routing">Marking extra actions for routing</a> <a href="#marking-extra-actions-for-routing">Marking extra actions for routing</a>
</li> </li>
@ -542,9 +546,15 @@ urlpatterns = router.urls
def destroy(self, request, pk=None): def destroy(self, request, pk=None):
pass pass
</code></pre> </code></pre>
<p>During dispatch the name of the current action is available via the <code>.action</code> attribute. <h2 id="introspecting-viewset-actions"><a class="toclink" href="#introspecting-viewset-actions">Introspecting ViewSet actions</a></h2>
You may inspect <code>.action</code> to adjust behaviour based on the current action.</p> <p>During dispatch, the following attributes are available on the <code>ViewSet</code>.</p>
<p>For example, you could restrict permissions to everything except the <code>list</code> action similar to this:</p> <ul>
<li><code>basename</code> - the base to use for the URL names that are created.</li>
<li><code>action</code> - the name of the current action (e.g., <code>list</code>, <code>create</code>).</li>
<li><code>detail</code> - boolean indicating if the current action is configured for a list or detail view.</li>
<li><code>suffix</code> - the display suffix for the viewset type - mirrors the <code>detail</code> attribute.</li>
</ul>
<p>You may inspect these attributes to adjust behaviour based on the current action. For example, you could restrict permissions to everything except the <code>list</code> action similar to this:</p>
<pre><code>def get_permissions(self): <pre><code>def get_permissions(self):
""" """
Instantiates and returns the list of permissions that this view requires. Instantiates and returns the list of permissions that this view requires.
@ -556,13 +566,11 @@ You may inspect <code>.action</code> to adjust behaviour based on the current ac
return [permission() for permission in permission_classes] return [permission() for permission in permission_classes]
</code></pre> </code></pre>
<h2 id="marking-extra-actions-for-routing"><a class="toclink" href="#marking-extra-actions-for-routing">Marking extra actions for routing</a></h2> <h2 id="marking-extra-actions-for-routing"><a class="toclink" href="#marking-extra-actions-for-routing">Marking extra actions for routing</a></h2>
<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>If you have ad-hoc methods that should be routable, you can mark them as such with the <code>@action</code> decorator. Like regular actions, extra actions may be intended for either a list of objects, or a single instance. To indicate this, set the <code>detail</code> argument to <code>True</code> or <code>False</code>. The router will configure its URL patterns accordingly. e.g., the <code>DefaultRouter</code> will configure detail actions to contain <code>pk</code> in their URL patterns.</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>A more complete example of extra actions:</p>
<p>For example:</p>
<pre><code>from django.contrib.auth.models import User <pre><code>from django.contrib.auth.models import User
from rest_framework import status from rest_framework import status, viewsets
from rest_framework import viewsets from rest_framework.decorators import action
from rest_framework.decorators import detail_route, list_route
from rest_framework.response import Response from rest_framework.response import Response
from myapp.serializers import UserSerializer, PasswordSerializer from myapp.serializers import UserSerializer, PasswordSerializer
@ -573,7 +581,7 @@ class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all() queryset = User.objects.all()
serializer_class = UserSerializer serializer_class = UserSerializer
@detail_route(methods=['post']) @action(methods=['post'], detail=True)
def set_password(self, request, pk=None): def set_password(self, request, pk=None):
user = self.get_object() user = self.get_object()
serializer = PasswordSerializer(data=request.data) serializer = PasswordSerializer(data=request.data)
@ -585,7 +593,7 @@ class UserViewSet(viewsets.ModelViewSet):
return Response(serializer.errors, return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@list_route() @action(detail=False)
def recent_users(self, request): def recent_users(self, request):
recent_users = User.objects.all().order('-last_login') recent_users = User.objects.all().order('-last_login')
@ -597,17 +605,18 @@ class UserViewSet(viewsets.ModelViewSet):
serializer = self.get_serializer(recent_users, many=True) serializer = self.get_serializer(recent_users, many=True)
return Response(serializer.data) return Response(serializer.data)
</code></pre> </code></pre>
<p>The decorators can additionally take extra arguments that will be set for the routed view only. For example...</p> <p>The decorator can additionally take extra arguments that will be set for the routed view only. For example:</p>
<pre><code> @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf]) <pre><code> @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf])
def set_password(self, request, pk=None): def set_password(self, request, pk=None):
... ...
</code></pre> </code></pre>
<p>These 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> <p>These decorator will route <code>GET</code> requests by default, but may also accept other HTTP methods by setting the <code>methods</code> argument. For example:</p>
<pre><code> @detail_route(methods=['post', 'delete']) <pre><code> @action(methods=['post', 'delete'], detail=True)
def unset_password(self, request, pk=None): def unset_password(self, request, pk=None):
... ...
</code></pre> </code></pre>
<p>The two new actions will then be available at the urls <code>^users/{pk}/set_password/$</code> and <code>^users/{pk}/unset_password/$</code></p> <p>The two new actions will then be available at the urls <code>^users/{pk}/set_password/$</code> and <code>^users/{pk}/unset_password/$</code></p>
<p>To view all extra actions, call the <code>.get_extra_actions()</code> method.</p>
<h2 id="reversing-action-urls"><a class="toclink" href="#reversing-action-urls">Reversing action URLs</a></h2> <h2 id="reversing-action-urls"><a class="toclink" href="#reversing-action-urls">Reversing action URLs</a></h2>
<p>If you need to get the URL of an action, use the <code>.reverse_action()</code> method. This is a convenience wrapper for <code>reverse()</code>, automatically passing the view's <code>request</code> object and prepending the <code>url_name</code> with the <code>.basename</code> attribute.</p> <p>If you need to get the URL of an action, use the <code>.reverse_action()</code> method. This is a convenience wrapper for <code>reverse()</code>, automatically passing the view's <code>request</code> object and prepending the <code>url_name</code> with the <code>.basename</code> attribute.</p>
<p>Note that the <code>basename</code> is provided by the router during <code>ViewSet</code> registration. If you are not using a router, then you must provide the <code>basename</code> argument to the <code>.as_view()</code> method.</p> <p>Note that the <code>basename</code> is provided by the router during <code>ViewSet</code> registration. If you are not using a router, then you must provide the <code>basename</code> argument to the <code>.as_view()</code> method.</p>
@ -616,7 +625,12 @@ class UserViewSet(viewsets.ModelViewSet):
'http://localhost:8000/api/users/1/set_password' 'http://localhost:8000/api/users/1/set_password'
</code></pre> </code></pre>
<p>The <code>url_name</code> argument should match the same argument to the <code>@list_route</code> and <code>@detail_route</code> decorators. Additionally, this can be used to reverse the default <code>list</code> and <code>detail</code> routes.</p> <p>Alternatively, you can use the <code>url_name</code> attribute set by the <code>@action</code> decorator.</p>
<pre><code class="python">&gt;&gt;&gt; view.reverse_action(view.set_password.url_name, args=['1'])
'http://localhost:8000/api/users/1/set_password'
</code></pre>
<p>The <code>url_name</code> argument for <code>.reverse_action()</code> should match the same argument to the <code>@action</code> decorator. Additionally, this method can be used to reverse the default actions, such as <code>list</code> and <code>create</code>.</p>
<hr /> <hr />
<h1 id="api-reference"><a class="toclink" href="#api-reference">API Reference</a></h1> <h1 id="api-reference"><a class="toclink" href="#api-reference">API Reference</a></h1>
<h2 id="viewset"><a class="toclink" href="#viewset">ViewSet</a></h2> <h2 id="viewset"><a class="toclink" href="#viewset">ViewSet</a></h2>

View File

@ -160,9 +160,19 @@ body, .navbar .navbar-inner .container-fluid{
margin: 0 auto; margin: 0 auto;
} }
body{ /* Replacement for `body { background-attachment: fixed; }`, which
background: url("../img/grid.png") repeat-x; has performance issues when scrolling on large displays. */
background-attachment: fixed; body::before {
content: ' ';
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: #f8f8f8;
background: url(../img/grid.png) repeat-x;
will-change: transform;
z-index: -1;
} }

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,7 @@
<url> <url>
<loc>http://www.django-rest-framework.org//</loc> <loc>http://www.django-rest-framework.org//</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
@ -13,49 +13,49 @@
<url> <url>
<loc>http://www.django-rest-framework.org//tutorial/quickstart/</loc> <loc>http://www.django-rest-framework.org//tutorial/quickstart/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//tutorial/1-serialization/</loc> <loc>http://www.django-rest-framework.org//tutorial/1-serialization/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//tutorial/2-requests-and-responses/</loc> <loc>http://www.django-rest-framework.org//tutorial/2-requests-and-responses/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//tutorial/3-class-based-views/</loc> <loc>http://www.django-rest-framework.org//tutorial/3-class-based-views/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//tutorial/4-authentication-and-permissions/</loc> <loc>http://www.django-rest-framework.org//tutorial/4-authentication-and-permissions/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//tutorial/5-relationships-and-hyperlinked-apis/</loc> <loc>http://www.django-rest-framework.org//tutorial/5-relationships-and-hyperlinked-apis/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//tutorial/6-viewsets-and-routers/</loc> <loc>http://www.django-rest-framework.org//tutorial/6-viewsets-and-routers/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//tutorial/7-schemas-and-client-libraries/</loc> <loc>http://www.django-rest-framework.org//tutorial/7-schemas-and-client-libraries/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
@ -65,163 +65,163 @@
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/requests/</loc> <loc>http://www.django-rest-framework.org//api-guide/requests/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/responses/</loc> <loc>http://www.django-rest-framework.org//api-guide/responses/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/views/</loc> <loc>http://www.django-rest-framework.org//api-guide/views/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/generic-views/</loc> <loc>http://www.django-rest-framework.org//api-guide/generic-views/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/viewsets/</loc> <loc>http://www.django-rest-framework.org//api-guide/viewsets/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/routers/</loc> <loc>http://www.django-rest-framework.org//api-guide/routers/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/parsers/</loc> <loc>http://www.django-rest-framework.org//api-guide/parsers/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/renderers/</loc> <loc>http://www.django-rest-framework.org//api-guide/renderers/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/serializers/</loc> <loc>http://www.django-rest-framework.org//api-guide/serializers/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/fields/</loc> <loc>http://www.django-rest-framework.org//api-guide/fields/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/relations/</loc> <loc>http://www.django-rest-framework.org//api-guide/relations/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/validators/</loc> <loc>http://www.django-rest-framework.org//api-guide/validators/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/authentication/</loc> <loc>http://www.django-rest-framework.org//api-guide/authentication/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/permissions/</loc> <loc>http://www.django-rest-framework.org//api-guide/permissions/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/throttling/</loc> <loc>http://www.django-rest-framework.org//api-guide/throttling/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/filtering/</loc> <loc>http://www.django-rest-framework.org//api-guide/filtering/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/pagination/</loc> <loc>http://www.django-rest-framework.org//api-guide/pagination/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/versioning/</loc> <loc>http://www.django-rest-framework.org//api-guide/versioning/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/content-negotiation/</loc> <loc>http://www.django-rest-framework.org//api-guide/content-negotiation/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/metadata/</loc> <loc>http://www.django-rest-framework.org//api-guide/metadata/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/schemas/</loc> <loc>http://www.django-rest-framework.org//api-guide/schemas/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/format-suffixes/</loc> <loc>http://www.django-rest-framework.org//api-guide/format-suffixes/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/reverse/</loc> <loc>http://www.django-rest-framework.org//api-guide/reverse/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/exceptions/</loc> <loc>http://www.django-rest-framework.org//api-guide/exceptions/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/status-codes/</loc> <loc>http://www.django-rest-framework.org//api-guide/status-codes/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/testing/</loc> <loc>http://www.django-rest-framework.org//api-guide/testing/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//api-guide/settings/</loc> <loc>http://www.django-rest-framework.org//api-guide/settings/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
@ -231,151 +231,151 @@
<url> <url>
<loc>http://www.django-rest-framework.org//topics/documenting-your-api/</loc> <loc>http://www.django-rest-framework.org//topics/documenting-your-api/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/api-clients/</loc> <loc>http://www.django-rest-framework.org//topics/api-clients/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/internationalization/</loc> <loc>http://www.django-rest-framework.org//topics/internationalization/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/ajax-csrf-cors/</loc> <loc>http://www.django-rest-framework.org//topics/ajax-csrf-cors/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/html-and-forms/</loc> <loc>http://www.django-rest-framework.org//topics/html-and-forms/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/browser-enhancements/</loc> <loc>http://www.django-rest-framework.org//topics/browser-enhancements/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/browsable-api/</loc> <loc>http://www.django-rest-framework.org//topics/browsable-api/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/rest-hypermedia-hateoas/</loc> <loc>http://www.django-rest-framework.org//topics/rest-hypermedia-hateoas/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/third-party-packages/</loc> <loc>http://www.django-rest-framework.org//topics/third-party-packages/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/tutorials-and-resources/</loc> <loc>http://www.django-rest-framework.org//topics/tutorials-and-resources/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/contributing/</loc> <loc>http://www.django-rest-framework.org//topics/contributing/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/project-management/</loc> <loc>http://www.django-rest-framework.org//topics/project-management/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/jobs/</loc> <loc>http://www.django-rest-framework.org//topics/jobs/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/3.0-announcement/</loc> <loc>http://www.django-rest-framework.org//topics/3.0-announcement/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/3.1-announcement/</loc> <loc>http://www.django-rest-framework.org//topics/3.1-announcement/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/3.2-announcement/</loc> <loc>http://www.django-rest-framework.org//topics/3.2-announcement/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/3.3-announcement/</loc> <loc>http://www.django-rest-framework.org//topics/3.3-announcement/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/3.4-announcement/</loc> <loc>http://www.django-rest-framework.org//topics/3.4-announcement/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/3.5-announcement/</loc> <loc>http://www.django-rest-framework.org//topics/3.5-announcement/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/3.6-announcement/</loc> <loc>http://www.django-rest-framework.org//topics/3.6-announcement/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/3.7-announcement/</loc> <loc>http://www.django-rest-framework.org//topics/3.7-announcement/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/kickstarter-announcement/</loc> <loc>http://www.django-rest-framework.org//topics/kickstarter-announcement/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/mozilla-grant/</loc> <loc>http://www.django-rest-framework.org//topics/mozilla-grant/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/funding/</loc> <loc>http://www.django-rest-framework.org//topics/funding/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>
<url> <url>
<loc>http://www.django-rest-framework.org//topics/release-notes/</loc> <loc>http://www.django-rest-framework.org//topics/release-notes/</loc>
<lastmod>2018-01-15</lastmod> <lastmod>2018-04-03</lastmod>
<changefreq>daily</changefreq> <changefreq>daily</changefreq>
</url> </url>

View File

@ -784,7 +784,7 @@ urlpatterns = [
/static/rest_framework/js/coreapi-0.1.1.js /static/rest_framework/js/coreapi-0.1.1.js
/docs/schema.js /docs/schema.js
--&gt; --&gt;
{% load staticfiles %} {% load static %}
&lt;script src="{% static 'rest_framework/js/coreapi-0.1.1.js' %}"&gt;&lt;/script&gt; &lt;script src="{% static 'rest_framework/js/coreapi-0.1.1.js' %}"&gt;&lt;/script&gt;
&lt;script src="{% url 'api-docs:schema-js' %}"&gt;&lt;/script&gt; &lt;script src="{% url 'api-docs:schema-js' %}"&gt;&lt;/script&gt;
</code></pre> </code></pre>

View File

@ -490,9 +490,13 @@
<li>If a ticket hasn't had much activity and it addresses something you need, then comment on the ticket and try to find out what's needed to get it moving again.</li> <li>If a ticket hasn't had much activity and it addresses something you need, then comment on the ticket and try to find out what's needed to get it moving again.</li>
</ul> </ul>
<h1 id="development"><a class="toclink" href="#development">Development</a></h1> <h1 id="development"><a class="toclink" href="#development">Development</a></h1>
<p>To start developing on Django REST framework, clone the repo:</p> <p>To start developing on Django REST framework, first create a Fork from the
<pre><code>git clone git@github.com:encode/django-rest-framework.git <a href="https://github.com/encode/django-rest-framework">Django REST Framework repo</a> on GitHub.</p>
<p>Then clone your fork. The clone command will look like this, with your GitHub
username instead of YOUR-USERNAME:</p>
<pre><code>git clone https://github.com/YOUR-USERNAME/Spoon-Knife
</code></pre> </code></pre>
<p>See GitHub's <a href="https://help.github.com/articles/fork-a-repo/"><em>Fork a Repo</em></a> Guide for more help.</p>
<p>Changes should broadly follow the <a href="https://www.python.org/dev/peps/pep-0008/">PEP 8</a> style conventions, and we recommend you set up your editor to automatically indicate non-conforming styles.</p> <p>Changes should broadly follow the <a href="https://www.python.org/dev/peps/pep-0008/">PEP 8</a> style conventions, and we recommend you set up your editor to automatically indicate non-conforming styles.</p>
<h2 id="testing"><a class="toclink" href="#testing">Testing</a></h2> <h2 id="testing"><a class="toclink" href="#testing">Testing</a></h2>
<p>To run the tests, clone the repository, and then:</p> <p>To run the tests, clone the repository, and then:</p>

View File

@ -505,6 +505,7 @@ For example:</p>
<li><code>generator_class</code>: Default <code>rest_framework.schemas.SchemaGenerator</code>. May be used to specify a <code>SchemaGenerator</code> subclass to be passed to the <code>SchemaView</code>.</li> <li><code>generator_class</code>: Default <code>rest_framework.schemas.SchemaGenerator</code>. May be used to specify a <code>SchemaGenerator</code> subclass to be passed to the <code>SchemaView</code>.</li>
<li><code>authentication_classes</code>: Default <code>api_settings.DEFAULT_AUTHENTICATION_CLASSES</code>. May be used to pass custom authentication classes to the <code>SchemaView</code>.</li> <li><code>authentication_classes</code>: Default <code>api_settings.DEFAULT_AUTHENTICATION_CLASSES</code>. May be used to pass custom authentication classes to the <code>SchemaView</code>.</li>
<li><code>permission_classes</code>: Default <code>api_settings.DEFAULT_PERMISSION_CLASSES</code> May be used to pass custom permission classes to the <code>SchemaView</code>.</li> <li><code>permission_classes</code>: Default <code>api_settings.DEFAULT_PERMISSION_CLASSES</code> May be used to pass custom permission classes to the <code>SchemaView</code>.</li>
<li><code>renderer_classes</code>: Default <code>None</code>. May be used to pass custom renderer classes to the <code>SchemaView</code>.</li>
</ul> </ul>
<h4 id="get_docs_view"><a class="toclink" href="#get_docs_view"><code>get_docs_view</code></a></h4> <h4 id="get_docs_view"><a class="toclink" href="#get_docs_view"><code>get_docs_view</code></a></h4>
<ul> <ul>
@ -515,7 +516,8 @@ For example:</p>
<li><code>patterns</code>: Default <code>None</code>. A list of URLs to inspect when generating the schema. If <code>None</code> project's URL conf will be used.</li> <li><code>patterns</code>: Default <code>None</code>. A list of URLs to inspect when generating the schema. If <code>None</code> project's URL conf will be used.</li>
<li><code>generator_class</code>: Default <code>rest_framework.schemas.SchemaGenerator</code>. May be used to specify a <code>SchemaGenerator</code> subclass to be passed to the <code>SchemaView</code>.</li> <li><code>generator_class</code>: Default <code>rest_framework.schemas.SchemaGenerator</code>. May be used to specify a <code>SchemaGenerator</code> subclass to be passed to the <code>SchemaView</code>.</li>
<li><code>authentication_classes</code>: Default <code>api_settings.DEFAULT_AUTHENTICATION_CLASSES</code>. May be used to pass custom authentication classes to the <code>SchemaView</code>.</li> <li><code>authentication_classes</code>: Default <code>api_settings.DEFAULT_AUTHENTICATION_CLASSES</code>. May be used to pass custom authentication classes to the <code>SchemaView</code>.</li>
<li><code>permission_classes</code>: Default <code>api_settings.DEFAULT_PERMISSION_CLASSES</code> May be used to pass custom permission classes to the <code>SchemaView</code>.</li> <li><code>permission_classes</code>: Default <code>api_settings.DEFAULT_PERMISSION_CLASSES</code>. May be used to pass custom permission classes to the <code>SchemaView</code>.</li>
<li><code>renderer_classes</code>: Default <code>None</code>. May be used to pass custom renderer classes to the <code>SchemaView</code>. If <code>None</code> the <code>SchemaView</code> will be configured with <code>DocumentationRenderer</code> and <code>CoreJSONRenderer</code> renderers, corresponding to the (default) <code>html</code> and <code>corejson</code> formats.</li>
</ul> </ul>
<h4 id="get_schemajs_view"><a class="toclink" href="#get_schemajs_view"><code>get_schemajs_view</code></a></h4> <h4 id="get_schemajs_view"><a class="toclink" href="#get_schemajs_view"><code>get_schemajs_view</code></a></h4>
<ul> <ul>
@ -528,6 +530,20 @@ For example:</p>
<li><code>authentication_classes</code>: Default <code>api_settings.DEFAULT_AUTHENTICATION_CLASSES</code>. May be used to pass custom authentication classes to the <code>SchemaView</code>.</li> <li><code>authentication_classes</code>: Default <code>api_settings.DEFAULT_AUTHENTICATION_CLASSES</code>. May be used to pass custom authentication classes to the <code>SchemaView</code>.</li>
<li><code>permission_classes</code>: Default <code>api_settings.DEFAULT_PERMISSION_CLASSES</code> May be used to pass custom permission classes to the <code>SchemaView</code>.</li> <li><code>permission_classes</code>: Default <code>api_settings.DEFAULT_PERMISSION_CLASSES</code> May be used to pass custom permission classes to the <code>SchemaView</code>.</li>
</ul> </ul>
<h3 id="customising-code-samples"><a class="toclink" href="#customising-code-samples">Customising code samples</a></h3>
<p>The built-in API documentation includes automatically generated code samples for
each of the available API client libraries.</p>
<p>You may customise these samples by subclassing <code>DocumentationRenderer</code>, setting
<code>languages</code> to the list of languages you wish to support:</p>
<pre><code>from rest_framework.renderers import DocumentationRenderer
class CustomRenderer(DocumentationRenderer):
languages = ['ruby', 'go']
</code></pre>
<p>For each language you need to provide an <code>intro</code> template, detailing installation instructions and such,
plus a generic template for making API requests, that can be filled with individual request details.
See the <a href="https://github.com/encode/django-rest-framework/tree/master/rest_framework/templates/rest_framework/docs/langs">templates for the bundled languages</a> for examples.</p>
<hr /> <hr />
<h2 id="third-party-packages"><a class="toclink" href="#third-party-packages">Third party packages</a></h2> <h2 id="third-party-packages"><a class="toclink" href="#third-party-packages">Third party packages</a></h2>
<p>There are a number of mature third-party packages for providing API documentation.</p> <p>There are a number of mature third-party packages for providing API documentation.</p>

View File

@ -750,7 +750,7 @@ DRF is one of the core reasons why Django is top choice among web frameworks tod
<p>For further enquires please contact <a href=mailto:funding@django-rest-framework.org>funding@django-rest-framework.org</a>.</p> <p>For further enquires please contact <a href=mailto:funding@django-rest-framework.org>funding@django-rest-framework.org</a>.</p>
<hr /> <hr />
<h2 id="accountability"><a class="toclink" href="#accountability">Accountability</a></h2> <h2 id="accountability"><a class="toclink" href="#accountability">Accountability</a></h2>
<p>In an effort to keep the project as transparent as possible, we are releasing <a href="http://www.encode.io/reports/november-2017">monthly progress reports</a> and regularly include financial reports and cost breakdowns.</p> <p>In an effort to keep the project as transparent as possible, we are releasing <a href="http://www.encode.io/reports/february-2018">monthly progress reports</a> and regularly include financial reports and cost breakdowns.</p>
<!-- Begin MailChimp Signup Form --> <!-- Begin MailChimp Signup Form -->
<p><link href="//cdn-images.mailchimp.com/embedcode/classic-10_7.css" rel="stylesheet" type="text/css"> <p><link href="//cdn-images.mailchimp.com/embedcode/classic-10_7.css" rel="stylesheet" type="text/css">

View File

@ -420,6 +420,7 @@
<li><a href="https://www.technojobs.co.uk/django-jobs">https://www.technojobs.co.uk/django-jobs</a></li> <li><a href="https://www.technojobs.co.uk/django-jobs">https://www.technojobs.co.uk/django-jobs</a></li>
<li><a href="https://remoteok.io/remote-django-jobs">https://remoteok.io/remote-django-jobs</a></li> <li><a href="https://remoteok.io/remote-django-jobs">https://remoteok.io/remote-django-jobs</a></li>
<li><a href="https://www.remotepython.com/jobs/">https://www.remotepython.com/jobs/</a></li> <li><a href="https://www.remotepython.com/jobs/">https://www.remotepython.com/jobs/</a></li>
<li><a href="https://weworkcontract.com/python-contract-jobs">https://weworkcontract.com/python-contract-jobs</a></li>
</ul> </ul>
<p>Know of any other great resources for Django REST Framework jobs that are missing in our list? Please <a href="https://github.com/encode/django-rest-framework">submit a pull request</a> or <a href="mailto:anna@django-rest-framework.org">email us</a>.</p> <p>Know of any other great resources for Django REST Framework jobs that are missing in our list? Please <a href="https://github.com/encode/django-rest-framework">submit a pull request</a> or <a href="mailto:anna@django-rest-framework.org">email us</a>.</p>
<p>Wonder how else you can help? One of the best ways you can help Django REST Framework is to ask interviewers if their company is signed up for <a href="https://fund.django-rest-framework.org/topics/funding/">REST Framework sponsorship</a> yet.</p> <p>Wonder how else you can help? One of the best ways you can help Django REST Framework is to ask interviewers if their company is signed up for <a href="https://fund.django-rest-framework.org/topics/funding/">REST Framework sponsorship</a> yet.</p>

View File

@ -398,6 +398,10 @@
<a href="#upgrading">Upgrading</a> <a href="#upgrading">Upgrading</a>
</li> </li>
<li>
<a href="#38x-series">3.8.x series</a>
</li>
<li> <li>
<a href="#37x-series">3.7.x series</a> <a href="#37x-series">3.7.x series</a>
</li> </li>
@ -473,10 +477,116 @@
<p>To upgrade Django REST framework to the latest version, use pip:</p> <p>To upgrade Django REST framework to the latest version, use pip:</p>
<pre><code>pip install -U djangorestframework <pre><code>pip install -U djangorestframework
</code></pre> </code></pre>
<p>You can determine your currently installed version using <code>pip freeze</code>:</p> <p>You can determine your currently installed version using <code>pip show</code>:</p>
<pre><code>pip freeze | grep djangorestframework <pre><code>pip show djangorestframework
</code></pre> </code></pre>
<hr /> <hr />
<h2 id="38x-series"><a class="toclink" href="#38x-series">3.8.x series</a></h2>
<h3 id="380"><a class="toclink" href="#380">3.8.0</a></h3>
<p><strong>Date</strong>: <a href="https://github.com/encode/django-rest-framework/milestone/61?closed=1">3rd April 2018</a></p>
<ul>
<li>
<p><strong>Breaking Change</strong>: Alter <code>read_only</code> plus <code>default</code> behaviour. <a href="https://github.com/encode/django-rest-framework/issues/5886">#5886</a></p>
<p><code>read_only</code> fields will now <strong>always</strong> be excluded from writable fields.</p>
<p>Previously <code>read_only</code> fields with a <code>default</code> value would use the <code>default</code> for create and update operations.</p>
<p>In order to maintain the old behaviour you may need to pass the value of <code>read_only</code> fields when calling <code>save()</code> in
the view:</p>
<pre><code>def perform_create(self, serializer):
serializer.save(owner=self.request.user)
</code></pre>
<p>Alternatively you may override <code>save()</code> or <code>create()</code> or <code>update()</code> on the serialiser as appropriate.
* Correct allow_null behaviour when required=False <a href="https://github.com/encode/django-rest-framework/issues/5888">#5888</a></p>
<p>Without an explicit <code>default</code>, <code>allow_null</code> implies a default of <code>null</code> for outgoing serialisation. Previously such
fields were being skipped when read-only or otherwise not required.</p>
<p><strong>Possible backwards compatibility break</strong> if you were relying on such fields being excluded from the outgoing
representation. In order to restore the old behaviour you can override <code>data</code> to exclude the field when <code>None</code>.</p>
<p>For example:</p>
<pre><code>@property
def data(self):
"""
Drop `maybe_none` field if None.
"""
data = super().data()
if 'maybe_none' in data and data['maybe_none'] is None:
del data['maybe_none']
return data
</code></pre>
</li>
<li>
<p>Refactor dynamic route generation and improve viewset action introspectibility. <a href="https://github.com/encode/django-rest-framework/issues/5705">#5705</a></p>
<p><code>ViewSet</code>s have been provided with new attributes and methods that allow
it to introspect its set of actions and the details of the current action.</p>
<ul>
<li>Merged <code>list_route</code> and <code>detail_route</code> into a single <code>action</code> decorator.</li>
<li>Get all extra actions on a <code>ViewSet</code> with <code>.get_extra_actions()</code>.</li>
<li>Extra actions now set the <code>url_name</code> and <code>url_path</code> on the decorated method.</li>
<li>Enable action url reversing through <code>.reverse_action()</code> method (added in 3.7.4)</li>
<li>Example reverse call: <code>self.reverse_action(self.custom_action.url_name)</code></li>
<li>Add <code>detail</code> initkwarg to indicate if the current action is operating on a
collection or a single instance.</li>
</ul>
<p>Additional changes:</p>
<ul>
<li>Deprecated <code>list_route</code> &amp; <code>detail_route</code> in favor of <code>action</code> decorator with <code>detail</code> boolean.</li>
<li>Deprecated dynamic list/detail route variants in favor of <code>DynamicRoute</code> with <code>detail</code> boolean.</li>
<li>Refactored the router's dynamic route generation.</li>
<li>Fix formatting of the 3.7.4 release note <a href="https://github.com/encode/django-rest-framework/issues/5704">#5704</a></li>
<li>Docs: Update DRF Writable Nested Serializers references <a href="https://github.com/encode/django-rest-framework/issues/5711">#5711</a></li>
<li>Docs: Fixed typo in auth URLs example. <a href="https://github.com/encode/django-rest-framework/issues/5713">#5713</a></li>
<li>Improve composite field child errors <a href="https://github.com/encode/django-rest-framework/issues/5655">#5655</a></li>
<li>Disable HTML inputs for dict/list fields <a href="https://github.com/encode/django-rest-framework/issues/5702">#5702</a></li>
<li>Fix typo in HostNameVersioning doc <a href="https://github.com/encode/django-rest-framework/issues/5709">#5709</a></li>
<li>Use rsplit to get module and classname for imports <a href="https://github.com/encode/django-rest-framework/issues/5712">#5712</a></li>
<li>Formalize URLPatternsTestCase <a href="https://github.com/encode/django-rest-framework/issues/5703">#5703</a></li>
<li>Add exception translation test <a href="https://github.com/encode/django-rest-framework/issues/5700">#5700</a></li>
<li>Test staticfiles <a href="https://github.com/encode/django-rest-framework/issues/5701">#5701</a></li>
<li>Add drf-yasg to documentation and schema 3rd party packages <a href="https://github.com/encode/django-rest-framework/issues/5720">#5720</a></li>
<li>Remove unused <code>compat._resolve_model()</code> <a href="https://github.com/encode/django-rest-framework/issues/5733">#5733</a></li>
<li>Drop compat workaround for unsupported Python 3.2 <a href="https://github.com/encode/django-rest-framework/issues/5734">#5734</a></li>
<li>Prefer <code>iter(dict)</code> over <code>iter(dict.keys())</code> <a href="https://github.com/encode/django-rest-framework/issues/5736">#5736</a></li>
<li>Pass <code>python_requires</code> argument to setuptools <a href="https://github.com/encode/django-rest-framework/issues/5739">#5739</a></li>
<li>Remove unused links from docs <a href="https://github.com/encode/django-rest-framework/issues/5735">#5735</a></li>
<li>Prefer https protocol for links in docs when available <a href="https://github.com/encode/django-rest-framework/issues/5729">#5729</a></li>
<li>Add HStoreField, postgres fields tests <a href="https://github.com/encode/django-rest-framework/issues/5654">#5654</a></li>
<li>Always fully qualify ValidationError in docs <a href="https://github.com/encode/django-rest-framework/issues/5751">#5751</a></li>
<li>Remove unreachable code from ManualSchema <a href="https://github.com/encode/django-rest-framework/issues/5766">#5766</a></li>
<li>Allowed customising API documentation code samples <a href="https://github.com/encode/django-rest-framework/issues/5752">#5752</a></li>
<li>Updated docs to use <code>pip show</code> <a href="https://github.com/encode/django-rest-framework/issues/5757">#5757</a></li>
<li>Load 'static' instead of 'staticfiles' in templates <a href="https://github.com/encode/django-rest-framework/issues/5773">#5773</a></li>
<li>Fixed a typo in <code>fields</code> docs <a href="https://github.com/encode/django-rest-framework/issues/5783">#5783</a></li>
<li>Refer to "NamespaceVersioning" instead of "NamespacedVersioning" in the documentation <a href="https://github.com/encode/django-rest-framework/issues/5754">#5754</a></li>
<li>ErrorDetail: add <code>__eq__</code>/<code>__ne__</code> and <code>__repr__</code> <a href="https://github.com/encode/django-rest-framework/issues/5787">#5787</a></li>
<li>Replace <code>background-attachment: fixed</code> in docs <a href="https://github.com/encode/django-rest-framework/issues/5777">#5777</a></li>
<li>Make 404 &amp; 403 responses consistent with <code>exceptions.APIException</code> output <a href="https://github.com/encode/django-rest-framework/issues/5763">#5763</a></li>
<li>Small fix to API documentation: schemas <a href="https://github.com/encode/django-rest-framework/issues/5796">#5796</a></li>
<li>Fix schema generation for PrimaryKeyRelatedField <a href="https://github.com/encode/django-rest-framework/issues/5764">#5764</a></li>
<li>Represent serializer DictField as an Object in schema <a href="https://github.com/encode/django-rest-framework/issues/5765">#5765</a></li>
<li>Added docs example reimplementing ObtainAuthToken <a href="https://github.com/encode/django-rest-framework/issues/5802">#5802</a></li>
<li>Add schema to the ObtainAuthToken view <a href="https://github.com/encode/django-rest-framework/issues/5676">#5676</a></li>
<li>Fix request formdata handling <a href="https://github.com/encode/django-rest-framework/issues/5800">#5800</a></li>
<li>Fix authtoken views imports <a href="https://github.com/encode/django-rest-framework/issues/5818">#5818</a></li>
<li>Update pytest, isort <a href="https://github.com/encode/django-rest-framework/issues/5815">#5815</a> <a href="https://github.com/encode/django-rest-framework/issues/5817">#5817</a> <a href="https://github.com/encode/django-rest-framework/issues/5894">#5894</a></li>
<li>Fixed active timezone handling for non ISO8601 datetimes. <a href="https://github.com/encode/django-rest-framework/issues/5833">#5833</a></li>
<li>Made TemplateHTMLRenderer render IntegerField inputs when value is <code>0</code>. <a href="https://github.com/encode/django-rest-framework/issues/5834">#5834</a></li>
<li>Corrected endpoint in tutorial instructions <a href="https://github.com/encode/django-rest-framework/issues/5835">#5835</a></li>
<li>Add Django Rest Framework Role Filters to Third party packages <a href="https://github.com/encode/django-rest-framework/issues/5809">#5809</a></li>
<li>Use single copy of static assets. Update jQuery <a href="https://github.com/encode/django-rest-framework/issues/5823">#5823</a></li>
<li>Changes ternary conditionals to be PEP308 compliant <a href="https://github.com/encode/django-rest-framework/issues/5827">#5827</a></li>
<li>Added links to 'A Todo List API with React' and 'Blog API' tutorials <a href="https://github.com/encode/django-rest-framework/issues/5837">#5837</a></li>
<li>Fix comment typo in ModelSerializer <a href="https://github.com/encode/django-rest-framework/issues/5844">#5844</a></li>
<li>Add admin to installed apps to avoid test failures. <a href="https://github.com/encode/django-rest-framework/issues/5870">#5870</a></li>
<li>Fixed schema for UUIDField in SimpleMetadata. <a href="https://github.com/encode/django-rest-framework/issues/5872">#5872</a></li>
<li>Corrected docs on router include with namespaces. <a href="https://github.com/encode/django-rest-framework/issues/5843">#5843</a></li>
<li>Test using model objects for dotted source default <a href="https://github.com/encode/django-rest-framework/issues/5880">#5880</a></li>
<li>Allow traversing nullable related fields <a href="https://github.com/encode/django-rest-framework/issues/5849">#5849</a></li>
<li>Added: Tutorial: Django REST with React (Django 2.0) <a href="https://github.com/encode/django-rest-framework/issues/5891">#5891</a></li>
<li>Add <code>LimitOffsetPagination.get_count</code> to allow method override <a href="https://github.com/encode/django-rest-framework/issues/5846">#5846</a></li>
<li>Don't show hidden fields in metadata <a href="https://github.com/encode/django-rest-framework/issues/5854">#5854</a></li>
<li>Enable OrderingFilter to handle an empty tuple (or list) for the 'ordering' field. <a href="https://github.com/encode/django-rest-framework/issues/5899">#5899</a></li>
<li>Added generic 500 and 400 JSON error handlers. <a href="https://github.com/encode/django-rest-framework/issues/5904">#5904</a></li>
</ul>
</li>
</ul>
<h2 id="37x-series"><a class="toclink" href="#37x-series">3.7.x series</a></h2> <h2 id="37x-series"><a class="toclink" href="#37x-series">3.7.x series</a></h2>
<h3 id="377"><a class="toclink" href="#377">3.7.7</a></h3> <h3 id="377"><a class="toclink" href="#377">3.7.7</a></h3>
<p><strong>Date</strong>: <a href="https://github.com/encode/django-rest-framework/milestone/65?closed=1">21st December 2017</a></p> <p><strong>Date</strong>: <a href="https://github.com/encode/django-rest-framework/milestone/65?closed=1">21st December 2017</a></p>
@ -1328,6 +1438,8 @@ Previously may have been stored internally as <code>None</code>.</p>
<!-- 3.7.5 --> <!-- 3.7.5 -->
<!-- 3.8.0 -->
</div> <!--/span--> </div> <!--/span-->
</div> <!--/row--> </div> <!--/row-->

View File

@ -445,6 +445,9 @@
<li><a href="https://richardtier.com/2014/03/06/110/">Check Credentials Using Django REST Framework</a></li> <li><a href="https://richardtier.com/2014/03/06/110/">Check Credentials Using Django REST Framework</a></li>
<li><a href="https://www.andreagrandi.it/2016/09/28/creating-production-ready-api-python-django-rest-framework-part-1/">Creating a Production Ready API with Python and Django REST Framework Part 1</a></li> <li><a href="https://www.andreagrandi.it/2016/09/28/creating-production-ready-api-python-django-rest-framework-part-1/">Creating a Production Ready API with Python and Django REST Framework Part 1</a></li>
<li><a href="https://www.andreagrandi.it/2016/10/01/creating-a-production-ready-api-with-python-and-django-rest-framework-part-2/">Creating a Production Ready API with Python and Django REST Framework Part 2</a></li> <li><a href="https://www.andreagrandi.it/2016/10/01/creating-a-production-ready-api-with-python-and-django-rest-framework-part-2/">Creating a Production Ready API with Python and Django REST Framework Part 2</a></li>
<li><a href="https://wsvincent.com/django-rest-framework-tutorial/">Django REST Framework Tutorial - Build a Blog API</a></li>
<li><a href="https://wsvincent.com/django-rest-framework-react-tutorial/">Django REST Framework &amp; React Tutorial - Build a Todo List API</a></li>
<li><a href="https://www.valentinog.com/blog/tutorial-api-django-rest-react/">Tutorial: Django REST with React (Django 2.0)</a></li>
</ul> </ul>
<h2 id="videos"><a class="toclink" href="#videos">Videos</a></h2> <h2 id="videos"><a class="toclink" href="#videos">Videos</a></h2>
<h3 id="talks"><a class="toclink" href="#talks">Talks</a></h3> <h3 id="talks"><a class="toclink" href="#talks">Talks</a></h3>

View File

@ -465,8 +465,8 @@ from pygments import highlight
representation of the code snippet. representation of the code snippet.
""" """
lexer = get_lexer_by_name(self.language) lexer = get_lexer_by_name(self.language)
linenos = self.linenos and 'table' or False linenos = 'table' if self.linenos else False
options = self.title and {'title': self.title} or {} options = {'title': self.title} if self.title else {}
formatter = HtmlFormatter(style=self.style, linenos=linenos, formatter = HtmlFormatter(style=self.style, linenos=linenos,
full=True, **options) full=True, **options)
self.highlighted = highlight(self.code, lexer, formatter) self.highlighted = highlight(self.code, lexer, formatter)

View File

@ -435,7 +435,7 @@ class UserViewSet(viewsets.ReadOnlyModelViewSet):
</code></pre> </code></pre>
<p>Here we've used the <code>ReadOnlyModelViewSet</code> class to automatically provide the default 'read-only' operations. We're still setting the <code>queryset</code> and <code>serializer_class</code> attributes exactly as we did when we were using regular views, but we no longer need to provide the same information to two separate classes.</p> <p>Here we've used the <code>ReadOnlyModelViewSet</code> class to automatically provide the default 'read-only' operations. We're still setting the <code>queryset</code> and <code>serializer_class</code> attributes exactly as we did when we were using regular views, but we no longer need to provide the same information to two separate classes.</p>
<p>Next we're going to replace the <code>SnippetList</code>, <code>SnippetDetail</code> and <code>SnippetHighlight</code> view classes. We can remove the three views, and again replace them with a single class.</p> <p>Next we're going to replace the <code>SnippetList</code>, <code>SnippetDetail</code> and <code>SnippetHighlight</code> view classes. We can remove the three views, and again replace them with a single class.</p>
<pre><code>from rest_framework.decorators import detail_route <pre><code>from rest_framework.decorators import action
from rest_framework.response import Response from rest_framework.response import Response
class SnippetViewSet(viewsets.ModelViewSet): class SnippetViewSet(viewsets.ModelViewSet):
@ -450,7 +450,7 @@ class SnippetViewSet(viewsets.ModelViewSet):
permission_classes = (permissions.IsAuthenticatedOrReadOnly, permission_classes = (permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly,) IsOwnerOrReadOnly,)
@detail_route(renderer_classes=[renderers.StaticHTMLRenderer]) @action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
def highlight(self, request, *args, **kwargs): def highlight(self, request, *args, **kwargs):
snippet = self.get_object() snippet = self.get_object()
return Response(snippet.highlighted) return Response(snippet.highlighted)
@ -459,9 +459,9 @@ class SnippetViewSet(viewsets.ModelViewSet):
serializer.save(owner=self.request.user) serializer.save(owner=self.request.user)
</code></pre> </code></pre>
<p>This time we've used the <code>ModelViewSet</code> class in order to get the complete set of default read and write operations.</p> <p>This time we've used the <code>ModelViewSet</code> class in order to get the complete set of default read and write operations.</p>
<p>Notice that we've also used the <code>@detail_route</code> decorator to create a custom action, named <code>highlight</code>. This decorator can be used to add any custom endpoints that don't fit into the standard <code>create</code>/<code>update</code>/<code>delete</code> style.</p> <p>Notice that we've also used the <code>@action</code> decorator to create a custom action, named <code>highlight</code>. This decorator can be used to add any custom endpoints that don't fit into the standard <code>create</code>/<code>update</code>/<code>delete</code> style.</p>
<p>Custom actions which use the <code>@detail_route</code> decorator will respond to <code>GET</code> requests by default. We can use the <code>methods</code> argument if we wanted an action that responded to <code>POST</code> requests.</p> <p>Custom actions which use the <code>@action</code> decorator will respond to <code>GET</code> requests by default. We can use the <code>methods</code> argument if we wanted an action that responded to <code>POST</code> requests.</p>
<p>The URLs for custom actions by default depend on the method name itself. If you want to change the way url should be constructed, you can include url_path as a decorator keyword argument.</p> <p>The URLs for custom actions by default depend on the method name itself. If you want to change the way url should be constructed, you can include <code>url_path</code> as a decorator keyword argument.</p>
<h2 id="binding-viewsets-to-urls-explicitly"><a class="toclink" href="#binding-viewsets-to-urls-explicitly">Binding ViewSets to URLs explicitly</a></h2> <h2 id="binding-viewsets-to-urls-explicitly"><a class="toclink" href="#binding-viewsets-to-urls-explicitly">Binding ViewSets to URLs explicitly</a></h2>
<p>The handler methods only get bound to the actions when we define the URLConf. <p>The handler methods only get bound to the actions when we define the URLConf.
To see what's going on under the hood let's first explicitly create a set of views from our ViewSets.</p> To see what's going on under the hood let's first explicitly create a set of views from our ViewSets.</p>

View File

@ -461,7 +461,7 @@ urlpatterns = [
] ]
</code></pre> </code></pre>
<p>If you visit the API root endpoint in a browser you should now see <code>corejson</code> <p>If you visit the <code>/schema/</code> endpoint in a browser you should now see <code>corejson</code>
representation become available as an option.</p> representation become available as an option.</p>
<p><img alt="Schema format" src="../../img/corejson-format.png" /></p> <p><img alt="Schema format" src="../../img/corejson-format.png" /></p>
<p>We can also request the schema from the command line, by specifying the desired <p>We can also request the schema from the command line, by specifying the desired