Deployed a81e60ff with MkDocs version: 0.16.3

This commit is contained in:
Carlton Gibson 2017-12-20 15:34:31 +01:00
parent 75523da09d
commit 834580c7cd
23 changed files with 465 additions and 173 deletions

View File

@ -718,6 +718,9 @@ already exist. To change this and other behaviour, consult the
</ul>
<p>You <em>may</em> also override the <code>.authenticate_header(self, request)</code> method. If implemented, it should return a string that will be used as the value of the <code>WWW-Authenticate</code> header in a <code>HTTP 401 Unauthorized</code> response.</p>
<p>If the <code>.authenticate_header()</code> method is not overridden, the authentication scheme will return <code>HTTP 403 Forbidden</code> responses when an unauthenticated request is denied access.</p>
<hr />
<p><strong>Note:</strong> When your custom authenticator is invoked by the request object's <code>.user</code> or <code>.auth</code> properties, you may see an <code>AttributeError</code> re-raised as a <code>WrappedAttributeError</code>. This is necessary to prevent the original exception from being suppressed by the outer property access. Python will not recognize that the <code>AttributeError</code> orginates from your custom authenticator and will instead assume that the request object does not have a <code>.user</code> or <code>.auth</code> property. These errors should be fixed or otherwise handled by your authenticator.</p>
<hr />
<h2 id="example"><a class="toclink" href="#example">Example</a></h2>
<p>The following example will authenticate any incoming request as the user given by the username in a custom request header named 'X_USERNAME'.</p>
<pre><code>from django.contrib.auth.models import User

View File

@ -636,6 +636,7 @@ Set to false if this field is not required to be present during deserialization.
<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 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>
<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>
@ -683,6 +684,7 @@ color_channel = serializers.ChoiceField(
<h2 id="booleanfield"><a class="toclink" href="#booleanfield">BooleanField</a></h2>
<p>A boolean representation.</p>
<p>When using HTML encoded form input be aware that omitting a value will always be treated as setting a field to <code>False</code>, even if it has a <code>default=True</code> option specified. This is because HTML checkbox inputs represent the unchecked state by omitting the value, so REST framework treats omission as if it is an empty checkbox input.</p>
<p>Note that default <code>BooleanField</code> instances will be generated with a <code>required=False</code> option (since Django <code>models.BooleanField</code> is always <code>blank=True</code>). If you want to change this behaviour explicitly declare the <code>BooleanField</code> on the serializer class.</p>
<p>Corresponds to <code>django.db.models.fields.BooleanField</code>.</p>
<p><strong>Signature:</strong> <code>BooleanField()</code></p>
<h2 id="nullbooleanfield"><a class="toclink" href="#nullbooleanfield">NullBooleanField</a></h2>
@ -841,7 +843,6 @@ color_channel = serializers.ChoiceField(
Corresponds to <code>django.db.models.fields.DurationField</code></p>
<p>The <code>validated_data</code> for these fields will contain a <code>datetime.timedelta</code> instance.
The representation is a string following this format <code>'[DD] [HH:[MM:]]ss[.uuuuuu]'</code>.</p>
<p><strong>Note:</strong> This field is only available with Django versions &gt;= 1.8.</p>
<p><strong>Signature:</strong> <code>DurationField()</code></p>
<hr />
<h1 id="choice-selection-fields"><a class="toclink" href="#choice-selection-fields">Choice selection fields</a></h1>
@ -981,6 +982,7 @@ class UserSerializer(serializers.ModelSerializer):
<p>The <code>to_internal_value()</code> method is called to restore a primitive datatype into its internal python representation. This method should raise a <code>serializers.ValidationError</code> if the data is invalid.</p>
<p>Note that the <code>WritableField</code> class that was present in version 2.x no longer exists. You should subclass <code>Field</code> and override <code>to_internal_value()</code> if the field supports data input.</p>
<h2 id="examples"><a class="toclink" href="#examples">Examples</a></h2>
<h3 id="a-basic-custom-field"><a class="toclink" href="#a-basic-custom-field">A Basic Custom Field</a></h3>
<p>Let's look at an example of serializing a class that represents an RGB color value:</p>
<pre><code>class Color(object):
"""
@ -1017,7 +1019,7 @@ class ColorField(serializers.Field):
"""
return obj.__class__.__name__
</code></pre>
<h4 id="raising-validation-errors"><a class="toclink" href="#raising-validation-errors">Raising validation errors</a></h4>
<h3 id="raising-validation-errors"><a class="toclink" href="#raising-validation-errors">Raising validation errors</a></h3>
<p>Our <code>ColorField</code> class above currently does not perform any data validation.
To indicate invalid data, we should raise a <code>serializers.ValidationError</code>, like so:</p>
<pre><code>def to_internal_value(self, data):
@ -1059,6 +1061,128 @@ def to_internal_value(self, data):
return Color(red, green, blue)
</code></pre>
<p>This style keeps your error messages cleaner and more separated from your code, and should be preferred.</p>
<h3 id="using-source"><a class="toclink" href="#using-source">Using <code>source='*'</code></a></h3>
<p>Here we'll take an example of a <em>flat</em> <code>DataPoint</code> model with <code>x_coordinate</code> and <code>y_coordinate</code> attributes.</p>
<pre><code>class DataPoint(models.Model):
label = models.CharField(max_length=50)
x_coordinate = models.SmallIntegerField()
y_coordinate = models.SmallIntegerField()
</code></pre>
<p>Using a custom field and <code>source='*'</code> we can provide a nested representation of
the coordinate pair:</p>
<pre><code>class CoordinateField(serializers.Field):
def to_representation(self, obj):
ret = {
"x": obj.x_coordinate,
"y": obj.y_coordinate
}
return ret
def to_internal_value(self, data):
ret = {
"x_coordinate": data["x"],
"y_coordinate": data["y"],
}
return ret
class DataPointSerializer(serializers.ModelSerializer):
coordinates = CoordinateField(source='*')
class Meta:
model = DataPoint
fields = ['label', 'coordinates']
</code></pre>
<p>Note that this example doesn't handle validation. Partly for that reason, in a
real project, the coordinate nesting might be better handled with a nested serialiser
using <code>source='*'</code>, with two <code>IntegerField</code> instances, each with their own <code>source</code>
pointing to the relevant field.</p>
<p>The key points from the example, though, are:</p>
<ul>
<li>
<p><code>to_representation</code> is passed the entire <code>DataPoint</code> object and must map from that
to the desired output.</p>
<pre><code>&gt;&gt;&gt; instance = DataPoint(label='Example', x_coordinate=1, y_coordinate=2)
&gt;&gt;&gt; out_serializer = DataPointSerializer(instance)
&gt;&gt;&gt; out_serializer.data
ReturnDict([('label', 'testing'), ('coordinates', {'x': 1, 'y': 2})])
</code></pre>
</li>
<li>
<p>Unless our field is to be read-only, <code>to_internal_value</code> must map back to a dict
suitable for updating our target object. With <code>source='*'</code>, the return from
<code>to_internal_value</code> will update the root validated data dictionary, rather than a single key.</p>
<pre><code>&gt;&gt;&gt; data = {
... "label": "Second Example",
... "coordinates": {
... "x": 3,
... "y": 4,
... }
... }
&gt;&gt;&gt; in_serializer = DataPointSerializer(data=data)
&gt;&gt;&gt; in_serializer.is_valid()
True
&gt;&gt;&gt; in_serializer.validated_data
OrderedDict([('label', 'Second Example'),
('y_coordinate', 4),
('x_coordinate', 3)])
</code></pre>
</li>
</ul>
<p>For completeness lets do the same thing again but with the nested serialiser
approach suggested above:</p>
<pre><code>class NestedCoordinateSerializer(serializers.Serializer):
x = serializers.IntegerField(source='x_coordinate')
y = serializers.IntegerField(source='y_coordinate')
class DataPointSerializer(serializers.ModelSerializer):
coordinates = NestedCoordinateSerializer(source='*')
class Meta:
model = DataPoint
fields = ['label', 'coordinates']
</code></pre>
<p>Here the mapping between the target and source attribute pairs (<code>x</code> and
<code>x_coordinate</code>, <code>y</code> and <code>y_coordinate</code>) is handled in the <code>IntegerField</code>
declarations. It's our <code>NestedCoordinateSerializer</code> that takes <code>source='*'</code>.</p>
<p>Our new <code>DataPointSerializer</code> exhibits the same behaviour as the custom field
approach.</p>
<p>Serialising:</p>
<pre><code>&gt;&gt;&gt; out_serializer = DataPointSerializer(instance)
&gt;&gt;&gt; out_serializer.data
ReturnDict([('label', 'testing'),
('coordinates', OrderedDict([('x', 1), ('y', 2)]))])
</code></pre>
<p>Deserialising:</p>
<pre><code>&gt;&gt;&gt; in_serializer = DataPointSerializer(data=data)
&gt;&gt;&gt; in_serializer.is_valid()
True
&gt;&gt;&gt; in_serializer.validated_data
OrderedDict([('label', 'still testing'),
('x_coordinate', 3),
('y_coordinate', 4)])
</code></pre>
<p>But we also get the built-in validation for free:</p>
<pre><code>&gt;&gt;&gt; invalid_data = {
... "label": "still testing",
... "coordinates": {
... "x": 'a',
... "y": 'b',
... }
... }
&gt;&gt;&gt; invalid_serializer = DataPointSerializer(data=invalid_data)
&gt;&gt;&gt; invalid_serializer.is_valid()
False
&gt;&gt;&gt; invalid_serializer.errors
ReturnDict([('coordinates',
{'x': ['A valid integer is required.'],
'y': ['A valid integer is required.']})])
</code></pre>
<p>For this reason, the nested serialiser approach would be the first to try. You
would use the custom field approach when the nested serialiser becomes infeasible
or overly complex.</p>
<h1 id="third-party-packages"><a class="toclink" href="#third-party-packages">Third party packages</a></h1>
<p>The following third party packages are also available.</p>
<h2 id="drf-compound-fields"><a class="toclink" href="#drf-compound-fields">DRF Compound Fields</a></h2>

View File

@ -612,8 +612,8 @@ class UserList(generics.ListCreateAPIView):
</code></pre>
<p>Note that if your API doesn't include any object level permissions, you may optionally exclude the <code>self.check_object_permissions</code>, and simply return the object from the <code>get_object_or_404</code> lookup.</p>
<h4 id="filter_querysetself-queryset"><a class="toclink" href="#filter_querysetself-queryset"><code>filter_queryset(self, queryset)</code></a></h4>
<p>Given a queryset, filter it with whichever filter backends are in use, returning a new queryset. </p>
<p>For example: </p>
<p>Given a queryset, filter it with whichever filter backends are in use, returning a new queryset.</p>
<p>For example:</p>
<pre><code>def filter_queryset(self, queryset):
filter_backends = (CategoryFilter,)

View File

@ -624,7 +624,7 @@ else:
# Check permissions for write request
</code></pre>
<hr />
<p><strong>Note</strong>: The instance-level <code>has_object_permission</code> method will only be called if the view-level <code>has_permission</code> checks have already passed. Also note that in order for the instance-level checks to run, the view code should explicitly call <code>.check_object_permissions(request, obj)</code>. If you are using the generic views then this will be handled for you by default.</p>
<p><strong>Note</strong>: The instance-level <code>has_object_permission</code> method will only be called if the view-level <code>has_permission</code> checks have already passed. Also note that in order for the instance-level checks to run, the view code should explicitly call <code>.check_object_permissions(request, obj)</code>. If you are using the generic views then this will be handled for you by default. (Function-based views will need to check object permissions explicitly, raising <code>PermissionDenied</code> on failure.)</p>
<hr />
<p>Custom permissions will raise a <code>PermissionDenied</code> exception if the test fails. To change the error message associated with the exception, implement a <code>message</code> attribute directly on your custom permission. Otherwise the <code>default_detail</code> attribute from <code>PermissionDenied</code> will be used.</p>
<pre><code>from rest_framework import permissions

View File

@ -534,6 +534,8 @@
<p>The <code>APIView</code> class or <code>@api_view</code> decorator will ensure that this property is automatically set to a list of <code>Authentication</code> instances, based on the <code>authentication_classes</code> set on the view or based on the <code>DEFAULT_AUTHENTICATORS</code> setting.</p>
<p>You won't typically need to access this property.</p>
<hr />
<p><strong>Note:</strong> You may see a <code>WrappedAttributeError</code> raised when calling the <code>.user</code> or <code>.auth</code> properties. These errors originate from an authenticator as a standard <code>AttributeError</code>, however it's necessary that they be re-raised as a different exception type in order to prevent them from being suppressed by the outer property access. Python will not recognize that the <code>AttributeError</code> orginates from the authenticator and will instaed assume that the request object does not have a <code>.user</code> or <code>.auth</code> property. The authenticator will need to be fixed.</p>
<hr />
<h1 id="browser-enhancements"><a class="toclink" href="#browser-enhancements">Browser enhancements</a></h1>
<p>REST framework supports a few browser enhancements such as browser-based <code>PUT</code>, <code>PATCH</code> and <code>DELETE</code> forms.</p>
<h2 id="method"><a class="toclink" href="#method">.method</a></h2>

View File

@ -634,6 +634,15 @@ coreapi_link = auto_schema.get_link(...)
</code></pre>
<p>(In compiling the schema, <code>SchemaGenerator</code> calls <code>view.schema.get_link()</code> for
each view, allowed method and path.)</p>
<hr />
<p><strong>Note</strong>: For basic <code>APIView</code> subclasses, default introspection is essentially
limited to the URL kwarg path parameters. For <code>GenericAPIView</code>
subclasses, which includes all the provided class based views, <code>AutoSchema</code> will
attempt to introspect serialiser, pagination and filter fields, as well as
provide richer path field descriptions. (The key hooks here are the relevant
<code>GenericAPIView</code> attributes and methods: <code>get_serializer</code>, <code>pagination_class</code>,
<code>filter_backends</code> and so on.)</p>
<hr />
<p>To customise the <code>Link</code> generation you may:</p>
<ul>
<li>
@ -989,6 +998,25 @@ that do not expect a request body.</p>
<p>Return a list of <code>coreapi.Link()</code> instances, as returned by the <code>get_schema_fields()</code> method on any pagination class used by the view.</p>
<h3 id="get_filter_fieldsself-path-method"><a class="toclink" href="#get_filter_fieldsself-path-method">get_filter_fields(self, path, method)</a></h3>
<p>Return a list of <code>coreapi.Link()</code> instances, as returned by the <code>get_schema_fields()</code> method of any filter classes used by the view.</p>
<h3 id="get_manual_fieldsself-path-method"><a class="toclink" href="#get_manual_fieldsself-path-method">get_manual_fields(self, path, method)</a></h3>
<p>Return a list of <code>coreapi.Field()</code> instances to be added to or replace generated fields. Defaults to (optional) <code>manual_fields</code> passed to <code>AutoSchema</code> constructor.</p>
<p>May be overridden to customise manual fields by <code>path</code> or <code>method</code>. For example, a per-method adjustment may look like this:</p>
<pre><code class="python">def get_manual_fields(self, path, method):
&quot;&quot;&quot;Example adding per-method fields.&quot;&quot;&quot;
extra_fields = []
if method=='GET':
extra_fields = # ... list of extra fields for GET ...
if method=='POST':
extra_fields = # ... list of extra fields for POST ...
manual_fields = super().get_manual_fields()
return manual_fields + extra_fields
</code></pre>
<h3 id="update_fieldsfields-update_with"><a class="toclink" href="#update_fieldsfields-update_with">update_fields(fields, update_with)</a></h3>
<p>Utility <code>staticmethod</code>. Encapsulates logic to add or replace fields from a list
by <code>Field.name</code>. May be overridden to adjust replacement criteria.</p>
<h2 id="manualschema"><a class="toclink" href="#manualschema">ManualSchema</a></h2>
<p>Allows manually providing a list of <code>coreapi.Field</code> instances for the schema,
plus an optional description.</p>

View File

@ -678,7 +678,7 @@ serializer.validated_data
# {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}
</code></pre>
<h2 id="saving-instances"><a class="toclink" href="#saving-instances">Saving instances</a></h2>
<p>If we want to be able to return complete object instances based on the validated data we need to implement one or both of the <code>.create()</code> and <code>update()</code> methods. For example:</p>
<p>If we want to be able to return complete object instances based on the validated data we need to implement one or both of the <code>.create()</code> and <code>.update()</code> methods. For example:</p>
<pre><code>class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
@ -879,7 +879,7 @@ serializer.errors
<li>Ignore the data and leave the instance as it is.</li>
<li>Raise a validation error.</li>
</ul>
<p>Here's an example for an <code>update()</code> method on our previous <code>UserSerializer</code> class.</p>
<p>Here's an example for an <code>.update()</code> method on our previous <code>UserSerializer</code> class.</p>
<pre><code> def update(self, instance, validated_data):
profile_data = validated_data.pop('profile')
# Unless the application properly enforces that this field is
@ -1009,6 +1009,7 @@ AccountSerializer():
<p>In the example above, if the <code>Account</code> model had 3 fields <code>account_name</code>, <code>users</code>, and <code>created</code>, this will result in the fields <code>account_name</code> and <code>created</code> to be serialized.</p>
<p>The names in the <code>fields</code> and <code>exclude</code> attributes will normally map to model fields on the model class.</p>
<p>Alternatively names in the <code>fields</code> options can map to properties or methods which take no arguments that exist on the model class.</p>
<p>Since version 3.3.0, it is <strong>mandatory</strong> to provide one of the attributes <code>fields</code> or <code>exclude</code>.</p>
<h2 id="specifying-nested-serialization"><a class="toclink" href="#specifying-nested-serialization">Specifying nested serialization</a></h2>
<p>The default <code>ModelSerializer</code> uses primary keys for relationships, but you can also easily generate nested representations using the <code>depth</code> option:</p>
<pre><code>class AccountSerializer(serializers.ModelSerializer):
@ -1392,9 +1393,16 @@ def all_high_scores(request):
<p>The signatures for these methods are as follows:</p>
<h4 id="to_representationself-obj"><a class="toclink" href="#to_representationself-obj"><code>.to_representation(self, obj)</code></a></h4>
<p>Takes the object instance that requires serialization, and should return a primitive representation. Typically this means returning a structure of built-in Python datatypes. The exact types that can be handled will depend on the render classes you have configured for your API.</p>
<p>May be overridden in order modify the representation style. For example:</p>
<pre><code>def to_representation(self, instance):
"""Convert `username` to lowercase."""
ret = super().to_representation(instance)
ret['username'] = ret['username'].lower()
return ret
</code></pre>
<h4 id="to_internal_valueself-data"><a class="toclink" href="#to_internal_valueself-data"><code>.to_internal_value(self, data)</code></a></h4>
<p>Takes the unvalidated incoming data as input and should return the validated data that will be made available as <code>serializer.validated_data</code>. The return value will also be passed to the <code>.create()</code> or <code>.update()</code> methods if <code>.save()</code> is called on the serializer class.</p>
<p>If any of the validation fails, then the method should raise a <code>serializers.ValidationError(errors)</code>. The <code>errors</code> argument should be a dictionary mapping field names (or <code>settings.NON_FIELD_ERRORS_KEY</code>) to a list of error messages. If you don't need to alter deserialization behavior and instead want to provide object-level validation, it's recommended that you intead override the <a href="#object-level-validation"><code>.validate()</code></a> method.</p>
<p>If any of the validation fails, then the method should raise a <code>serializers.ValidationError(errors)</code>. The <code>errors</code> argument should be a dictionary mapping field names (or <code>settings.NON_FIELD_ERRORS_KEY</code>) to a list of error messages. If you don't need to alter deserialization behavior and instead want to provide object-level validation, it's recommended that you instead override the <a href="#object-level-validation"><code>.validate()</code></a> method.</p>
<p>The <code>data</code> argument passed to this method will normally be the value of <code>request.data</code>, so the datatype it provides will depend on the parser classes you have configured for your API.</p>
<h2 id="serializer-inheritance"><a class="toclink" href="#serializer-inheritance">Serializer Inheritance</a></h2>
<p>Similar to Django forms, you can extend and reuse serializers through inheritance. This allows you to declare a common set of fields or methods on a parent class that can then be used in a number of serializers. For example,</p>

View File

@ -531,6 +531,9 @@ print api_settings.DEFAULT_AUTHENTICATION_CLASSES
<h4 id="default_content_negotiation_class"><a class="toclink" href="#default_content_negotiation_class">DEFAULT_CONTENT_NEGOTIATION_CLASS</a></h4>
<p>A content negotiation class, that determines how a renderer is selected for the response, given an incoming request.</p>
<p>Default: <code>'rest_framework.negotiation.DefaultContentNegotiation'</code></p>
<h4 id="default_schema_class"><a class="toclink" href="#default_schema_class">DEFAULT_SCHEMA_CLASS</a></h4>
<p>A view inspector class that will be used for schema generation.</p>
<p>Default: <code>'rest_framework.schemas.AutoSchema'</code></p>
<hr />
<h2 id="generic-view-settings"><a class="toclink" href="#generic-view-settings">Generic view settings</a></h2>
<p><em>The following settings control the behavior of the generic class-based views.</em></p>
@ -583,7 +586,9 @@ If set to <code>None</code> then generic filtering is disabled.</p>
<h2 id="authentication-settings"><a class="toclink" href="#authentication-settings">Authentication settings</a></h2>
<p><em>The following settings control the behavior of unauthenticated requests.</em></p>
<h4 id="unauthenticated_user"><a class="toclink" href="#unauthenticated_user">UNAUTHENTICATED_USER</a></h4>
<p>The class that should be used to initialize <code>request.user</code> for unauthenticated requests.</p>
<p>The class that should be used to initialize <code>request.user</code> for unauthenticated requests.
(If removing authentication entirely, e.g. by removing <code>django.contrib.auth</code> from
<code>INSTALLED_APPS</code>, set <code>UNAUTHENTICATED_USER</code> to <code>None</code>.)</p>
<p>Default: <code>django.contrib.auth.models.AnonymousUser</code></p>
<h4 id="unauthenticated_token"><a class="toclink" href="#unauthenticated_token">UNAUTHENTICATED_TOKEN</a></h4>
<p>The class that should be used to initialize <code>request.auth</code> for unauthenticated requests.</p>

View File

@ -482,6 +482,9 @@ class ListUsers(APIView):
usernames = [user.username for user in User.objects.all()]
return Response(usernames)
</code></pre>
<hr />
<p><strong>Note</strong>: The full methods, attributes on, and relations between Django REST Framework's <code>APIView</code>, <code>GenericAPIView</code>, various <code>Mixins</code>, and <code>Viewsets</code> can be initially complex. In addition to the documentation here, the <a href="http://www.cdrf.co">Classy Django REST Framework</a> resource provides a browsable reference, with full methods and attributes, for each of Django REST Framework's class-based views.</p>
<hr />
<h2 id="api-policy-attributes"><a class="toclink" href="#api-policy-attributes">API policy attributes</a></h2>
<p>The following attributes control the pluggable aspects of API views.</p>
<h3 id="renderer_classes"><a class="toclink" href="#renderer_classes">.renderer_classes</a></h3>

View File

@ -390,10 +390,18 @@
<a href="#example">Example</a>
</li>
<li>
<a href="#viewset-actions">ViewSet actions</a>
</li>
<li>
<a href="#marking-extra-actions-for-routing">Marking extra actions for routing</a>
</li>
<li>
<a href="#reversing-action-urls">Reversing action URLs</a>
</li>
<li class="main">
<a href="#api-reference">API Reference</a>
@ -505,8 +513,8 @@ urlpatterns = router.urls
<li>By using routers, we no longer need to deal with wiring up the URL conf ourselves.</li>
</ul>
<p>Both of these come with a trade-off. Using regular views and URL confs is more explicit and gives you more control. ViewSets are helpful if you want to get up and running quickly, or when you have a large API and you want to enforce a consistent URL configuration throughout.</p>
<h2 id="marking-extra-actions-for-routing"><a class="toclink" href="#marking-extra-actions-for-routing">Marking extra actions for routing</a></h2>
<p>The default routers included with REST framework will provide routes for a standard set of create/retrieve/update/destroy style operations, as shown below:</p>
<h2 id="viewset-actions"><a class="toclink" href="#viewset-actions">ViewSet actions</a></h2>
<p>The default routers included with REST framework will provide routes for a standard set of create/retrieve/update/destroy style actions, as shown below:</p>
<pre><code>class UserViewSet(viewsets.ViewSet):
"""
Example empty viewset demonstrating the standard
@ -534,6 +542,20 @@ urlpatterns = router.urls
def destroy(self, request, pk=None):
pass
</code></pre>
<p>During dispatch the name of the current action is available via the <code>.action</code> attribute.
You may inspect <code>.action</code> to adjust behaviour based on the current action.</p>
<p>For example, you could restrict permissions to everything except the <code>list</code> action similar to this:</p>
<pre><code>def get_permissions(self):
"""
Instantiates and returns the list of permissions that this view requires.
"""
if self.action == 'list':
permission_classes = [IsAuthenticated]
else:
permission_classes = [IsAdmin]
return [permission() for permission in permission_classes]
</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>
<p>If you have ad-hoc methods that you need to be routed to, you can mark them as requiring routing using the <code>@detail_route</code> or <code>@list_route</code> decorators.</p>
<p>The <code>@detail_route</code> decorator contains <code>pk</code> in its URL pattern and is intended for methods which require a single instance. The <code>@list_route</code> decorator is intended for methods which operate on a list of objects.</p>
<p>For example:</p>
@ -586,6 +608,15 @@ class UserViewSet(viewsets.ModelViewSet):
...
</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>
<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>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>Using the example from the previous section:</p>
<pre><code class="python">&gt;&gt;&gt; view.reverse_action('set-password', args=['1'])
'http://localhost:8000/api/users/1/set_password'
</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>
<hr />
<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>

View File

@ -578,10 +578,10 @@ pip install django-filter # Filtering support
<p>If you're intending to use the browsable API you'll probably also want to add REST framework's login and logout views. Add the following to your root <code>urls.py</code> file.</p>
<pre><code>urlpatterns = [
...
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
url(r'^api-auth/', include('rest_framework.urls'))
]
</code></pre>
<p>Note that the URL path can be whatever you want, but you must include <code>'rest_framework.urls'</code> with the <code>'rest_framework'</code> namespace. You may leave out the namespace in Django 1.9+, and REST framework will set it for you.</p>
<p>Note that the URL path can be whatever you want.</p>
<h2 id="example"><a class="toclink" href="#example">Example</a></h2>
<p>Let's take a look at a quick example of using REST framework to build a simple model-backed API.</p>
<p>We'll create a read-write API for accessing information on the users of our project.</p>

File diff suppressed because one or more lines are too long

View File

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

View File

@ -493,9 +493,9 @@ For example:</p>
"""
</code></pre>
<h3 id="documentation-api-reference"><a class="toclink" href="#documentation-api-reference"><code>documentation</code> API Reference</a></h3>
<p>The <code>rest_framework.documentation</code> module provides three helper functions to help configure the interactive API documentation, <code>include_docs_url</code> (usage shown above), <code>get_docs_view</code> and <code>get_schemajs_view</code>.</p>
<p><code>include_docs_url</code> employs <code>get_docs_view</code> and <code>get_schemajs_view</code> to generate the url patterns for the documentation page and JavaScript resource that exposes the API schema respectively. They expose the following options for customisation. (<code>get_docs_view</code> and <code>get_schemajs_view</code> ultimately call <code>rest_frameworks.schemas.get_schema_view()</code>, see the Schemas docs for more options there.)</p>
<h4 id="include_docs_url"><a class="toclink" href="#include_docs_url"><code>include_docs_url</code></a></h4>
<p>The <code>rest_framework.documentation</code> module provides three helper functions to help configure the interactive API documentation, <code>include_docs_urls</code> (usage shown above), <code>get_docs_view</code> and <code>get_schemajs_view</code>.</p>
<p><code>include_docs_urls</code> employs <code>get_docs_view</code> and <code>get_schemajs_view</code> to generate the url patterns for the documentation page and JavaScript resource that exposes the API schema respectively. They expose the following options for customisation. (<code>get_docs_view</code> and <code>get_schemajs_view</code> ultimately call <code>rest_frameworks.schemas.get_schema_view()</code>, see the Schemas docs for more options there.)</p>
<h4 id="include_docs_urls"><a class="toclink" href="#include_docs_urls"><code>include_docs_urls</code></a></h4>
<ul>
<li><code>title</code>: Default <code>None</code>. May be used to provide a descriptive title for the schema definition.</li>
<li><code>description</code>: Default <code>None</code>. May be used to provide a description for the schema definition.</li>
@ -608,15 +608,17 @@ out-of-the-box by Django Rest Framework. Its goals are:</p>
<h4 id="the-options-method"><a class="toclink" href="#the-options-method">The <code>OPTIONS</code> method</a></h4>
<p>REST framework APIs also support programmatically accessible descriptions, using the <code>OPTIONS</code> HTTP method. A view will respond to an <code>OPTIONS</code> request with metadata including the name, description, and the various media types it accepts and responds with.</p>
<p>When using the generic views, any <code>OPTIONS</code> requests will additionally respond with metadata regarding any <code>POST</code> or <code>PUT</code> actions available, describing which fields are on the serializer.</p>
<p>You can modify the response behavior to <code>OPTIONS</code> requests by overriding the <code>metadata</code> view method. For example:</p>
<pre><code>def metadata(self, request):
<p>You can modify the response behavior to <code>OPTIONS</code> requests by overriding the <code>options</code> view method and/or by providing a custom Metadata class. For example:</p>
<pre><code>def options(self, request, *args, **kwargs):
"""
Don't include the view description in OPTIONS responses.
"""
data = super(ExampleView, self).metadata(request)
meta = self.metadata_class()
data = meta.determine_metadata(request, self)
data.pop('description')
return data
</code></pre>
<p>See <a href="../../api-guide/metadata/">the Metadata docs</a> for more details.</p>
<hr />
<h2 id="the-hypermedia-approach"><a class="toclink" href="#the-hypermedia-approach">The hypermedia approach</a></h2>
<p>To be fully RESTful an API should present its available actions as hypermedia controls in the responses that it sends.</p>

View File

@ -555,6 +555,7 @@ form.signup {
<ul>
<li>The <a href="http://www.django-rest-framework.org/topics/3.4-announcement/">3.4</a> and <a href="http://www.django-rest-framework.org/topics/3.5-announcement/">3.5</a> releases, including schema generation for both Swagger and RAML, a Python client library, a Command Line client, and addressing of a large number of outstanding issues.</li>
<li>The <a href="http://www.django-rest-framework.org/topics/3.6-announcement/">3.6</a> release, including JavaScript client library, and API documentation, complete with auto-generated code samples.</li>
<li>The recent <a href="http://www.django-rest-framework.org/topics/3.7-announcement/">3.7 release</a>, made possible due to our collaborative funding model, focuses on improvements to schema generation and the interactive API documentation.</li>
<li>Tom Christie, the creator of Django REST framework, working on the project full-time.</li>
<li>Around 80-90 issues and pull requests closed per month since Tom Christie started working on the project full-time.</li>
<li>A community &amp; operations manager position part-time for 4 months, helping mature the business and grow sponsorship.</li>
@ -749,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>
<hr />
<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/september-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/november-2017">monthly progress reports</a> and regularly include financial reports and cost breakdowns.</p>
<!-- Begin MailChimp Signup Form -->
<p><link href="//cdn-images.mailchimp.com/embedcode/classic-10_7.css" rel="stylesheet" type="text/css">

View File

@ -478,13 +478,72 @@
</code></pre>
<hr />
<h2 id="37x-series"><a class="toclink" href="#37x-series">3.7.x series</a></h2>
<h3 id="374"><a class="toclink" href="#374">3.7.4</a></h3>
<p><strong>Date</strong>: <a href="https://github.com/encode/django-rest-framework/milestone/62?closed=1">20th December 2017</a></p>
<ul>
<li>
<p>Schema: Extract method for <code>manual_fields</code> processing <a href="https://github.com/encode/django-rest-framework/issues/5633">#5633</a></p>
<p>Allows for easier customisation of <code>manual_fields</code> processing, for example
to provide per-method manual fields. <code>AutoSchema</code> adds <code>get_manual_fields</code>,
as the intended override point, and a utility method <code>update_fields</code>, to
handle by-name field replacement from a list, which, in general, you are not
expected to override.</p>
<p>Note: <code>AutoSchema.__init__</code> now ensures <code>manual_fields</code> is a list.
Previously may have been stored internally as <code>None</code>.
<em> Remove ulrparse compatability shim; use six instead <a href="https://github.com/encode/django-rest-framework/issues/5579">#5579</a>
</em> Drop compat wrapper for <code>TimeDelta.total_seconds()</code> <a href="https://github.com/encode/django-rest-framework/issues/5577">#5577</a>
<em> Clean up all whitespace throughout project <a href="https://github.com/encode/django-rest-framework/issues/5578">#5578</a>
</em> Compat cleanup <a href="https://github.com/encode/django-rest-framework/issues/5581">#5581</a>
<em> Add pygments CSS block in browsable API views <a href="https://github.com/encode/django-rest-framework/issues/5584">#5584</a> <a href="https://github.com/encode/django-rest-framework/issues/5587">#5587</a>
</em> Remove <code>set_rollback()</code> from compat <a href="https://github.com/encode/django-rest-framework/issues/5591">#5591</a>
<em> Fix request body/POST access <a href="https://github.com/encode/django-rest-framework/issues/5590">#5590</a>
</em> Rename test to reference correct issue <a href="https://github.com/encode/django-rest-framework/issues/5610">#5610</a>
<em> Documentation Fixes <a href="https://github.com/encode/django-rest-framework/issues/5611">#5611</a> <a href="https://github.com/encode/django-rest-framework/issues/5612">#5612</a>
</em> Remove references to unsupported Django versions in docs and code <a href="https://github.com/encode/django-rest-framework/issues/5602">#5602</a>
<em> Test Serializer exclude for declared fields <a href="https://github.com/encode/django-rest-framework/issues/5599">#5599</a>
</em> Fixed schema generation for filter backends <a href="https://github.com/encode/django-rest-framework/issues/5613">#5613</a>
<em> Minor cleanup for ModelSerializer tests <a href="https://github.com/encode/django-rest-framework/issues/5598">#5598</a>
</em> Reimplement request attribute access w/ <code>__getattr__</code> <a href="https://github.com/encode/django-rest-framework/issues/5617">#5617</a>
<em> Fixed SchemaJSRenderer renders invalid Javascript <a href="https://github.com/encode/django-rest-framework/issues/5607">#5607</a>
</em> Make Django 2.0 support official/explicit <a href="https://github.com/encode/django-rest-framework/issues/5619">#5619</a>
<em> Perform type check on passed request argument <a href="https://github.com/encode/django-rest-framework/issues/5618">#5618</a>
</em> Fix AttributeError hiding on request authenticators <a href="https://github.com/encode/django-rest-framework/issues/5600">#5600</a>
<em> Update test requirements <a href="https://github.com/encode/django-rest-framework/issues/5626">#5626</a>
</em> Docs: <code>Serializer._declared_fields</code> enable modifying fields on a serializer <a href="https://github.com/encode/django-rest-framework/issues/5629">#5629</a>
<em> Fix packaging <a href="https://github.com/encode/django-rest-framework/issues/5624">#5624</a>
</em> Fix readme rendering for PyPI, add readme build to CI <a href="https://github.com/encode/django-rest-framework/issues/5625">#5625</a>
<em> Update tutorial <a href="https://github.com/encode/django-rest-framework/issues/5622">#5622</a>
</em> Non-required fields with <code>allow_null=True</code> should not imply a default value <a href="https://github.com/encode/django-rest-framework/issues/5639">#5639</a>
<em> Docs: Add <code>allow_null</code> serialization output note <a href="https://github.com/encode/django-rest-framework/issues/5641">#5641</a>
</em> Update to use the Django 2.0 release in tox.ini <a href="https://github.com/encode/django-rest-framework/issues/5645">#5645</a>
<em> Fix <code>Serializer.data</code> for Browsable API rendering when provided invalid <code>data</code> <a href="https://github.com/encode/django-rest-framework/issues/5646">#5646</a>
</em> Docs: Note AutoSchema limitations on bare APIView <a href="https://github.com/encode/django-rest-framework/issues/5649">#5649</a>
<em> Add <code>.basename</code> and <code>.reverse_action()</code> to ViewSet <a href="https://github.com/encode/django-rest-framework/issues/5648">#5648</a>
</em> Docs: Fix typos in serializers documentation <a href="https://github.com/encode/django-rest-framework/issues/5652">#5652</a>
<em> Fix <code>override_settings</code> compat <a href="https://github.com/encode/django-rest-framework/issues/5668">#5668</a>
</em> Add DEFAULT_SCHEMA_CLASS setting <a href="https://github.com/encode/django-rest-framework/issues/5658">#5658</a>
<em> Add docs note re generated BooleanField being <code>required=False</code> <a href="https://github.com/encode/django-rest-framework/issues/5665">#5665</a>
</em> Add 'dist' build <a href="https://github.com/encode/django-rest-framework/issues/5656">#5656</a>
<em> Fix typo in docstring <a href="https://github.com/encode/django-rest-framework/issues/5678">#5678</a>
</em> Docs: Add <code>UNAUTHENTICATED_USER = None</code> note <a href="https://github.com/encode/django-rest-framework/issues/5679">#5679</a>
<em> Update OPTIONS example from “Documenting Your API” <a href="https://github.com/encode/django-rest-framework/issues/5680">#5680</a>
</em> Docs: Add note on object permissions for FBVs <a href="https://github.com/encode/django-rest-framework/issues/5681">#5681</a>
<em> Docs: Add example to <code>to_representation</code> docs <a href="https://github.com/encode/django-rest-framework/issues/5682">#5682</a>
</em> Add link to Classy DRF in docs <a href="https://github.com/encode/django-rest-framework/issues/5683">#5683</a>
<em> Document ViewSet.action <a href="https://github.com/encode/django-rest-framework/issues/5685">#5685</a>
</em> Fix schema docs typo <a href="https://github.com/encode/django-rest-framework/issues/5687">#5687</a>
<em> Fix URL pattern parsing in schema generation <a href="https://github.com/encode/django-rest-framework/issues/5689">#5689</a>
</em> Add example using <code>source=*</code> to custom field docs. <a href="https://github.com/encode/django-rest-framework/issues/5688">#5688</a>
* Fix format_suffix_patterns behavior with Django 2 path() routes <a href="https://github.com/encode/django-rest-framework/issues/5691">#5691</a></p>
</li>
</ul>
<h3 id="373"><a class="toclink" href="#373">3.7.3</a></h3>
<p><strong>Date</strong>: <a href="https://github.com/encode/django-rest-framework/milestone/60?closed=1">6th Novemember 2017</a></p>
<p><strong>Date</strong>: <a href="https://github.com/encode/django-rest-framework/milestone/60?closed=1">6th November 2017</a></p>
<ul>
<li>Fix <code>AppRegistryNotReady</code> error from contrib.auth view imports <a href="https://github.com/encode/django-rest-framework/issues/5567">#5567</a></li>
</ul>
<h3 id="372"><a class="toclink" href="#372">3.7.2</a></h3>
<p><strong>Date</strong>: <a href="https://github.com/encode/django-rest-framework/milestone/59?closed=1">6th Novemember 2017</a></p>
<p><strong>Date</strong>: <a href="https://github.com/encode/django-rest-framework/milestone/59?closed=1">6th November 2017</a></p>
<ul>
<li>Fixed Django 2.1 compatibility due to removal of django.contrib.auth.login()/logout() views. <a href="https://github.com/encode/django-rest-framework/issues/5510">#5510</a></li>
<li>Add missing import for TextLexer. <a href="https://github.com/encode/django-rest-framework/issues/5512">#5512</a></li>
@ -1246,6 +1305,8 @@
<!-- 3.7.2 -->
<!-- 3.7.3 -->
<!-- 3.7.4 -->
</div> <!--/span-->

View File

@ -476,7 +476,6 @@ cd tutorial
'snippets.apps.SnippetsConfig',
)
</code></pre>
<p>Please note that if you're using Django &lt;1.9, you need to replace <code>snippets.apps.SnippetsConfig</code> with <code>snippets</code>.</p>
<p>Okay, we're ready to roll.</p>
<h2 id="creating-a-model-to-work-with"><a class="toclink" href="#creating-a-model-to-work-with">Creating a model to work with</a></h2>
<p>For the purposes of this tutorial we're going to start by creating a simple <code>Snippet</code> model that is used to store code snippets. Go ahead and edit the <code>snippets/models.py</code> file. Note: Good programming practices include comments. Although you will find them in our repository version of this tutorial code, we have omitted them here to focus on the code itself.</p>

View File

@ -519,7 +519,7 @@ def snippet_detail(request, pk):
<p>and</p>
<pre><code>def snippet_detail(request, pk, format=None):
</code></pre>
<p>Now update the <code>urls.py</code> file slightly, to append a set of <code>format_suffix_patterns</code> in addition to the existing URLs.</p>
<p>Now update the <code>snippets/urls.py</code> file slightly, to append a set of <code>format_suffix_patterns</code> in addition to the existing URLs.</p>
<pre><code>from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

View File

@ -471,7 +471,7 @@ class SnippetList(APIView):
return Response(status=status.HTTP_204_NO_CONTENT)
</code></pre>
<p>That's looking good. Again, it's still pretty similar to the function based view right now.</p>
<p>We'll also need to refactor our <code>urls.py</code> slightly now that we're using class-based views.</p>
<p>We'll also need to refactor our <code>snippets/urls.py</code> slightly now that we're using class-based views.</p>
<pre><code>from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

View File

@ -474,7 +474,7 @@ from pygments import highlight
</code></pre>
<p>When that's all done we'll need to update our database tables.
Normally we'd create a database migration in order to do that, but for the purposes of this tutorial, let's just delete the database and start again.</p>
<pre><code>rm -f tmp.db db.sqlite3
<pre><code>rm -f db.sqlite3
rm -r snippets/migrations
python manage.py makemigrations snippets
python manage.py migrate
@ -546,11 +546,10 @@ url(r'^users/(?P&lt;pk&gt;[0-9]+)/$', views.UserDetail.as_view()),
</code></pre>
<p>And, at the end of the file, add a pattern to include the login and logout views for the browsable API.</p>
<pre><code>urlpatterns += [
url(r'^api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
url(r'^api-auth/', include('rest_framework.urls'),
]
</code></pre>
<p>The <code>r'^api-auth/'</code> part of pattern can actually be whatever URL you want to use. The only restriction is that the included urls must use the <code>'rest_framework'</code> namespace. In Django 1.9+, REST framework will set the namespace, so you may leave it out.</p>
<p>The <code>r'^api-auth/'</code> part of pattern can actually be whatever URL you want to use.</p>
<p>Now if you open up the browser again and refresh the page you'll see a 'Login' link in the top right of the page. If you log in as one of the users you created earlier, you'll be able to create code snippets again.</p>
<p>Once you've created a few code snippets, navigate to the '/users/' endpoint, and notice that the representation includes a list of the snippet ids that are associated with each user, in each user's 'snippets' field.</p>
<h2 id="object-level-permissions"><a class="toclink" href="#object-level-permissions">Object level permissions</a></h2>
@ -594,11 +593,11 @@ class IsOwnerOrReadOnly(permissions.BasePermission):
}
</code></pre>
<p>We can make a successful request by including the username and password of one of the users we created earlier.</p>
<pre><code>http -a tom:password123 POST http://127.0.0.1:8000/snippets/ code="print 789"
<pre><code>http -a admin:password123 POST http://127.0.0.1:8000/snippets/ code="print 789"
{
"id": 1,
"owner": "tom",
"owner": "admin",
"title": "foo",
"code": "print 789",
"linenos": false,

View File

@ -536,21 +536,16 @@ urlpatterns = format_suffix_patterns([
views.UserDetail.as_view(),
name='user-detail')
])
# Login and logout views for the browsable API
urlpatterns += [
url(r'^api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
]
</code></pre>
<h2 id="adding-pagination"><a class="toclink" href="#adding-pagination">Adding pagination</a></h2>
<p>The list views for users and code snippets could end up returning quite a lot of instances, so really we'd like to make sure we paginate the results, and allow the API client to step through each of the individual pages.</p>
<p>We can change the default list style to use pagination, by modifying our <code>tutorial/settings.py</code> file slightly. Add the following setting:</p>
<p>We can change the default list style to use pagination, by modifying our <code>tutorial/settings.py</code> file slightly. Add the following setting:</p>
<pre><code>REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10
}
</code></pre>
<p>Note that settings in REST framework are all namespaced into a single dictionary setting, named 'REST_FRAMEWORK', which helps keep them well separated from your other project settings.</p>
<p>Note that settings in REST framework are all namespaced into a single dictionary setting, named <code>REST_FRAMEWORK</code>, which helps keep them well separated from your other project settings.</p>
<p>We could also customize the pagination style if we needed too, but in this case we'll just stick with the default.</p>
<h2 id="browsing-the-api"><a class="toclink" href="#browsing-the-api">Browsing the API</a></h2>
<p>If we open a browser and navigate to the browsable API, you'll find that you can now work your way around the API simply by following links.</p>

View File

@ -465,7 +465,7 @@ class SnippetViewSet(viewsets.ModelViewSet):
<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.
To see what's going on under the hood let's first explicitly create a set of views from our ViewSets.</p>
<p>In the <code>urls.py</code> file we bind our <code>ViewSet</code> classes into a set of concrete views.</p>
<p>In the <code>snippets/urls.py</code> file we bind our <code>ViewSet</code> classes into a set of concrete views.</p>
<pre><code>from snippets.views import SnippetViewSet, UserViewSet, api_root
from rest_framework import renderers
@ -502,10 +502,10 @@ user_detail = UserViewSet.as_view({
</code></pre>
<h2 id="using-routers"><a class="toclink" href="#using-routers">Using Routers</a></h2>
<p>Because we're using <code>ViewSet</code> classes rather than <code>View</code> classes, we actually don't need to design the URL conf ourselves. The conventions for wiring up resources into views and urls can be handled automatically, using a <code>Router</code> class. All we need to do is register the appropriate view sets with a router, and let it do the rest.</p>
<p>Here's our re-wired <code>urls.py</code> file.</p>
<p>Here's our re-wired <code>snippets/urls.py</code> file.</p>
<pre><code>from django.conf.urls import url, include
from snippets import views
from rest_framework.routers import DefaultRouter
from snippets import views
# Create a router and register our viewsets with it.
router = DefaultRouter()
@ -513,10 +513,8 @@ router.register(r'snippets', views.SnippetViewSet)
router.register(r'users', views.UserViewSet)
# The API URLs are now determined automatically by the router.
# Additionally, we include the login URLs for the browsable API.
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
url(r'^', include(router.urls))
]
</code></pre>
<p>Registering the viewsets with the router is similar to providing a urlpattern. We include two arguments - the URL prefix for the views, and the viewset itself.</p>

View File

@ -473,7 +473,7 @@ $ find .
<pre><code>python manage.py migrate
</code></pre>
<p>We'll also create an initial user named <code>admin</code> with a password of <code>password123</code>. We'll authenticate as that user later in our example.</p>
<pre><code>python manage.py createsuperuser
<pre><code>python manage.py createsuperuser --email admin@example.com --username admin
</code></pre>
<p>Once you've set up a database and initial user created and ready to go, open up the app's directory and we'll get coding...</p>
<h2 id="serializers"><a class="toclink" href="#serializers">Serializers</a></h2>
@ -539,18 +539,11 @@ urlpatterns = [
<p>Again, if we need more control over the API URLs we can simply drop down to using regular class-based views, and writing the URL conf explicitly.</p>
<p>Finally, we're including default login and logout views for use with the browsable API. That's optional, but useful if your API requires authentication and you want to use the browsable API.</p>
<h2 id="settings"><a class="toclink" href="#settings">Settings</a></h2>
<p>We'd also like to set a few global settings. We'd like to turn on pagination, and we want our API to only be accessible to admin users. The settings module will be in <code>tutorial/settings.py</code></p>
<p>Add <code>'rest_framework'</code> to <code>INSTALLED_APPS</code>. The settings module will be in <code>tutorial/settings.py</code></p>
<pre><code>INSTALLED_APPS = (
...
'rest_framework',
)
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAdminUser',
],
'PAGE_SIZE': 10
}
</code></pre>
<p>Okay, we're done.</p>
<hr />