mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-14 05:36:50 +03:00
Update documentation
This commit is contained in:
parent
9defb5ee9f
commit
ed93e13a1c
|
@ -65,7 +65,7 @@
|
|||
<a class="repo-link btn btn-inverse btn-small " rel="prev" href="../permissions">
|
||||
Next <i class="icon-arrow-right icon-white"></i>
|
||||
</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="next" href="../relations">
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="next" href="../validators">
|
||||
<i class="icon-arrow-left icon-white"></i> Previous
|
||||
</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li class="active" >
|
||||
<a href=".">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -761,7 +769,7 @@ class ExampleAuthentication(authentication.BaseAuthentication):
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -466,7 +474,7 @@ class NoNegotiationView(APIView):
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -389,6 +397,10 @@
|
|||
<a href="#throttled">Throttled</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#validationerror">ValidationError</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -484,7 +496,7 @@ class ServiceUnavailable(APIException):
|
|||
</code></pre>
|
||||
<h2 id="parseerror">ParseError</h2>
|
||||
<p><strong>Signature:</strong> <code>ParseError(detail=None)</code></p>
|
||||
<p>Raised if the request contains malformed data when accessing <code>request.DATA</code> or <code>request.FILES</code>.</p>
|
||||
<p>Raised if the request contains malformed data when accessing <code>request.data</code>.</p>
|
||||
<p>By default this exception results in a response with the HTTP status code "400 Bad Request".</p>
|
||||
<h2 id="authenticationfailed">AuthenticationFailed</h2>
|
||||
<p><strong>Signature:</strong> <code>AuthenticationFailed(detail=None)</code></p>
|
||||
|
@ -504,12 +516,25 @@ class ServiceUnavailable(APIException):
|
|||
<p>By default this exception results in a response with the HTTP status code "405 Method Not Allowed".</p>
|
||||
<h2 id="unsupportedmediatype">UnsupportedMediaType</h2>
|
||||
<p><strong>Signature:</strong> <code>UnsupportedMediaType(media_type, detail=None)</code></p>
|
||||
<p>Raised if there are no parsers that can handle the content type of the request data when accessing <code>request.DATA</code> or <code>request.FILES</code>.</p>
|
||||
<p>Raised if there are no parsers that can handle the content type of the request data when accessing <code>request.data</code>.</p>
|
||||
<p>By default this exception results in a response with the HTTP status code "415 Unsupported Media Type".</p>
|
||||
<h2 id="throttled">Throttled</h2>
|
||||
<p><strong>Signature:</strong> <code>Throttled(wait=None, detail=None)</code></p>
|
||||
<p>Raised when an incoming request fails the throttling checks.</p>
|
||||
<p>By default this exception results in a response with the HTTP status code "429 Too Many Requests".</p>
|
||||
<h2 id="validationerror">ValidationError</h2>
|
||||
<p><strong>Signature:</strong> <code>ValidationError(detail)</code></p>
|
||||
<p>The <code>ValidationError</code> exception is slightly different from the other <code>APIException</code> classes:</p>
|
||||
<ul>
|
||||
<li>The <code>detail</code> argument is mandatory, not optional.</li>
|
||||
<li>The <code>detail</code> argument may be a list or dictionary of error details, and may also be a nested data structure.</li>
|
||||
<li>By convention you should import the serializers module and use a fully qualified <code>ValidationError</code> style, in order to differentiate it from Django's built-in validation error. For example. <code>raise serializers.ValidationError('This field must be an integer value.')</code></li>
|
||||
</ul>
|
||||
<p>The <code>ValidationError</code> class should be used for serializer and field validation, and by validator classes. It is also raised when calling <code>serializer.is_valid</code> with the <code>raise_exception</code> keyword argument:</p>
|
||||
<pre><code>serializer.is_valid(raise_exception=True)
|
||||
</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>By default this exception results in a response with the HTTP status code "400 Bad Request".</p>
|
||||
|
||||
</div>
|
||||
<!--/span-->
|
||||
|
@ -524,7 +549,7 @@ class ServiceUnavailable(APIException):
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -349,31 +357,7 @@
|
|||
|
||||
|
||||
<li class="main">
|
||||
<a href="#generic-fields">Generic Fields</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#field">Field</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#writablefield">WritableField</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#modelfield">ModelField</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#serializermethodfield">SerializerMethodField</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="main">
|
||||
<a href="#typed-fields">Typed Fields</a>
|
||||
<a href="#boolean-fields">Boolean fields</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
@ -381,22 +365,22 @@
|
|||
<a href="#booleanfield">BooleanField</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#nullbooleanfield">NullBooleanField</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="main">
|
||||
<a href="#string-fields">String fields</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#charfield">CharField</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#urlfield">URLField</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#slugfield">SlugField</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#choicefield">ChoiceField</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#emailfield">EmailField</a>
|
||||
</li>
|
||||
|
@ -406,16 +390,20 @@
|
|||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#datetimefield">DateTimeField</a>
|
||||
<a href="#slugfield">SlugField</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#datefield">DateField</a>
|
||||
<a href="#urlfield">URLField</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#timefield">TimeField</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
<li class="main">
|
||||
<a href="#numeric-fields">Numeric fields</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#integerfield">IntegerField</a>
|
||||
|
@ -429,6 +417,54 @@
|
|||
<a href="#decimalfield">DecimalField</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="main">
|
||||
<a href="#date-and-time-fields">Date and time fields</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#datetimefield">DateTimeField</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#datefield">DateField</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#timefield">TimeField</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="main">
|
||||
<a href="#choice-selection-fields">Choice selection fields</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#choicefield">ChoiceField</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#multiplechoicefield">MultipleChoiceField</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="main">
|
||||
<a href="#file-upload-fields">File upload fields</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#parsers-and-file-uploads">Parsers and file uploads.</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#filefield">FileField</a>
|
||||
</li>
|
||||
|
@ -440,6 +476,42 @@
|
|||
|
||||
|
||||
|
||||
<li class="main">
|
||||
<a href="#composite-fields">Composite fields</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#listfield">ListField</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="main">
|
||||
<a href="#miscellaneous-fields">Miscellaneous fields</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#readonlyfield">ReadOnlyField</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#hiddenfield">HiddenField</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#modelfield">ModelField</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#serializermethodfield">SerializerMethodField</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="main">
|
||||
<a href="#custom-fields">Custom fields</a>
|
||||
</li>
|
||||
|
@ -492,21 +564,20 @@
|
|||
|
||||
|
||||
|
||||
<h1 id="serializer-fields">Serializer fields</h1>
|
||||
<hr />
|
||||
<p><strong>Note</strong>: This is the documentation for the <strong>version 3.0</strong> of REST framework. Documentation for <a href="http://tomchristie.github.io/rest-framework-2-docs/">version 2.4</a> is also available.</p>
|
||||
<hr />
|
||||
<h1 id="serializer-fields">Serializer fields</h1>
|
||||
<blockquote>
|
||||
<p>Each field in a Form class is responsible not only for validating data, but also for "cleaning" it — normalizing it to a consistent format.</p>
|
||||
<p>— <a href="https://docs.djangoproject.com/en/dev/ref/forms/api/#django.forms.Form.cleaned_data">Django documentation</a></p>
|
||||
</blockquote>
|
||||
<p>Serializer fields handle converting between primitive values and internal datatypes. They also deal with validating input values, as well as retrieving and setting the values from their parent objects.</p>
|
||||
<hr />
|
||||
<p><strong>Note:</strong> The serializer fields are declared in fields.py, but by convention you should import them using <code>from rest_framework import serializers</code> and refer to fields as <code>serializers.<FieldName></code>.</p>
|
||||
<p><strong>Note:</strong> The serializer fields are declared in <code>fields.py</code>, but by convention you should import them using <code>from rest_framework import serializers</code> and refer to fields as <code>serializers.<FieldName></code>.</p>
|
||||
<hr />
|
||||
<h2 id="core-arguments">Core arguments</h2>
|
||||
<p>Each serializer field class constructor takes at least these arguments. Some Field classes take additional, field-specific arguments, but the following should always be accepted:</p>
|
||||
<h3 id="source"><code>source</code></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>Field(source='get_absolute_url')</code>, or may use dotted notation to traverse attributes, such as <code>Field(source='user.email')</code>.</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. (See the implementation of the <code>PaginationSerializer</code> class for an example.)</p>
|
||||
<p>Defaults to the name of the field.</p>
|
||||
<h3 id="read_only"><code>read_only</code></h3>
|
||||
<p>Set this to <code>True</code> to ensure that the field is used when serializing a representation, but is not used when creating or updating an instance during deserialization.</p>
|
||||
<p>Defaults to <code>False</code></p>
|
||||
|
@ -517,111 +588,135 @@
|
|||
<p>Normally an error will be raised if a field is not supplied during deserialization.
|
||||
Set to false if this field is not required to be present during deserialization.</p>
|
||||
<p>Defaults to <code>True</code>.</p>
|
||||
<h3 id="allow_null"><code>allow_null</code></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>Defaults to <code>False</code></p>
|
||||
<h3 id="default"><code>default</code></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 behavior is to not populate the attribute at all.</p>
|
||||
<p>May be set to a function or other callable, in which case the value will be evaluated each time it is used.</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="source"><code>source</code></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('get_absolute_url')</code>, or may use dotted notation to traverse attributes, such as <code>EmailField(source='user.email')</code>.</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>Defaults to the name of the field.</p>
|
||||
<h3 id="validators"><code>validators</code></h3>
|
||||
<p>A list of Django validators that should be used to validate deserialized values.</p>
|
||||
<p>A list of validator functions which should be applied to the incoming field input, and which either raise a validation error or simply return. Validator functions should typically raise <code>serializers.ValidationError</code>, but Django's built-in <code>ValidationError</code> is also supported for compatibility with validators defined in the Django codebase or third party Django packages.</p>
|
||||
<h3 id="error_messages"><code>error_messages</code></h3>
|
||||
<p>A dictionary of error codes to error messages.</p>
|
||||
<h3 id="widget"><code>widget</code></h3>
|
||||
<p>Used only if rendering the field to HTML.
|
||||
This argument sets the widget that should be used to render the field. For more details, and a list of available widgets, see <a href="https://docs.djangoproject.com/en/dev/ref/forms/widgets/">the Django documentation on form widgets</a>.</p>
|
||||
<h3 id="label"><code>label</code></h3>
|
||||
<p>A short text string that may be used as the name of the field in HTML form fields or other descriptive elements.</p>
|
||||
<h3 id="help_text"><code>help_text</code></h3>
|
||||
<p>A text string that may be used as a description of the field in HTML form fields or other descriptive elements.</p>
|
||||
<hr />
|
||||
<h1 id="generic-fields">Generic Fields</h1>
|
||||
<p>These generic fields are used for representing arbitrary model fields or the output of model methods.</p>
|
||||
<h2 id="field">Field</h2>
|
||||
<p>A generic, <strong>read-only</strong> field. You can use this field for any attribute that does not need to support write operations.</p>
|
||||
<p>For example, using the following model.</p>
|
||||
<pre><code>from django.db import models
|
||||
from django.utils.timezone import now
|
||||
<h3 id="initial"><code>initial</code></h3>
|
||||
<p>A value that should be used for pre-populating the value of HTML form fields.</p>
|
||||
<h3 id="style"><code>style</code></h3>
|
||||
<p>A dictionary of key-value pairs that can be used to control how renderers should render the field. The API for this should still be considered experimental, and will be formalized with the 3.1 release.</p>
|
||||
<p>Two options are currently used in HTML form generation, <code>'input_type'</code> and <code>'base_template'</code>.</p>
|
||||
<pre><code># Use <input type="password"> for the input.
|
||||
password = serializers.CharField(
|
||||
style={'input_type': 'password'}
|
||||
)
|
||||
|
||||
class Account(models.Model):
|
||||
owner = models.ForeignKey('auth.user')
|
||||
name = models.CharField(max_length=100)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
payment_expiry = models.DateTimeField()
|
||||
|
||||
def has_expired(self):
|
||||
return now() > self.payment_expiry
|
||||
</code></pre>
|
||||
<p>A serializer definition that looked like this:</p>
|
||||
<pre><code>from rest_framework import serializers
|
||||
|
||||
class AccountSerializer(serializers.HyperlinkedModelSerializer):
|
||||
expired = serializers.Field(source='has_expired')
|
||||
|
||||
class Meta:
|
||||
model = Account
|
||||
fields = ('url', 'owner', 'name', 'expired')
|
||||
</code></pre>
|
||||
<p>Would produce output similar to:</p>
|
||||
<pre><code>{
|
||||
'url': 'http://example.com/api/accounts/3/',
|
||||
'owner': 'http://example.com/api/users/12/',
|
||||
'name': 'FooCorp business account',
|
||||
'expired': True
|
||||
# Use a radio input instead of a select input.
|
||||
color_channel = serializers.ChoiceField(
|
||||
choices=['red', 'green', 'blue']
|
||||
style = {'base_template': 'radio.html'}
|
||||
}
|
||||
</code></pre>
|
||||
<p>By default, the <code>Field</code> class will perform a basic translation of the source value into primitive datatypes, falling back to unicode representations of complex datatypes when necessary.</p>
|
||||
<p>You can customize this behavior by overriding the <code>.to_native(self, value)</code> method.</p>
|
||||
<h2 id="writablefield">WritableField</h2>
|
||||
<p>A field that supports both read and write operations. By itself <code>WritableField</code> does not perform any translation of input values into a given type. You won't typically use this field directly, but you may want to override it and implement the <code>.to_native(self, value)</code> and <code>.from_native(self, value)</code> methods.</p>
|
||||
<h2 id="modelfield">ModelField</h2>
|
||||
<p>A generic field that can be tied to any arbitrary model field. The <code>ModelField</code> class delegates the task of serialization/deserialization to its associated model field. This field can be used to create serializer fields for custom model fields, without having to create a new custom serializer field.</p>
|
||||
<p>The <code>ModelField</code> class is generally intended for internal use, but can be used by your API if needed. In order to properly instantiate a <code>ModelField</code>, it must be passed a field that is attached to an instantiated model. For example: <code>ModelField(model_field=MyModel()._meta.get_field('custom_field'))</code></p>
|
||||
<p><strong>Signature:</strong> <code>ModelField(model_field=<Django ModelField instance>)</code></p>
|
||||
<h2 id="serializermethodfield">SerializerMethodField</h2>
|
||||
<p>This is a read-only field. It gets its value by calling a method on the serializer class it is attached to. It can be used to add any sort of data to the serialized representation of your object. The field's constructor accepts a single argument, which is the name of the method on the serializer to be called. The method should accept a single argument (in addition to <code>self</code>), which is the object being serialized. It should return whatever you want to be included in the serialized representation of the object. For example:</p>
|
||||
<pre><code>from django.contrib.auth.models import User
|
||||
from django.utils.timezone import now
|
||||
from rest_framework import serializers
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
days_since_joined = serializers.SerializerMethodField('get_days_since_joined')
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
|
||||
def get_days_since_joined(self, obj):
|
||||
return (now() - obj.date_joined).days
|
||||
</code></pre>
|
||||
<p><strong>Note</strong>: The <code>style</code> argument replaces the old-style version 2.x <code>widget</code> keyword argument. Because REST framework 3 now uses templated HTML form generation, the <code>widget</code> option that was used to support Django built-in widgets can no longer be supported. Version 3.1 is planned to include public API support for customizing HTML form generation.</p>
|
||||
<hr />
|
||||
<h1 id="typed-fields">Typed Fields</h1>
|
||||
<p>These fields represent basic datatypes, and support both reading and writing values.</p>
|
||||
<h1 id="boolean-fields">Boolean fields</h1>
|
||||
<h2 id="booleanfield">BooleanField</h2>
|
||||
<p>A Boolean representation.</p>
|
||||
<p>A boolean representation.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.BooleanField</code>.</p>
|
||||
<p><strong>Signature:</strong> <code>BooleanField()</code></p>
|
||||
<h2 id="nullbooleanfield">NullBooleanField</h2>
|
||||
<p>A boolean representation that also accepts <code>None</code> as a valid value.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.NullBooleanField</code>.</p>
|
||||
<p><strong>Signature:</strong> <code>NullBooleanField()</code></p>
|
||||
<hr />
|
||||
<h1 id="string-fields">String fields</h1>
|
||||
<h2 id="charfield">CharField</h2>
|
||||
<p>A text representation, optionally validates the text to be shorter than <code>max_length</code> and longer than <code>min_length</code>.
|
||||
If <code>allow_none</code> is <code>False</code> (default), <code>None</code> values will be converted to an empty string.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.CharField</code>
|
||||
or <code>django.db.models.fields.TextField</code>.</p>
|
||||
<p><strong>Signature:</strong> <code>CharField(max_length=None, min_length=None, allow_none=False)</code></p>
|
||||
<h2 id="urlfield">URLField</h2>
|
||||
<p>Corresponds to <code>django.db.models.fields.URLField</code>. Uses Django's <code>django.core.validators.URLValidator</code> for validation.</p>
|
||||
<p><strong>Signature:</strong> <code>URLField(max_length=200, min_length=None)</code></p>
|
||||
<h2 id="slugfield">SlugField</h2>
|
||||
<p>Corresponds to <code>django.db.models.fields.SlugField</code>.</p>
|
||||
<p><strong>Signature:</strong> <code>SlugField(max_length=50, min_length=None)</code></p>
|
||||
<h2 id="choicefield">ChoiceField</h2>
|
||||
<p>A field that can accept a value out of a limited set of choices. Optionally takes a <code>blank_display_value</code> parameter that customizes the display value of an empty choice.</p>
|
||||
<p><strong>Signature:</strong> <code>ChoiceField(choices=(), blank_display_value=None)</code></p>
|
||||
<p>A text representation. Optionally validates the text to be shorter than <code>max_length</code> and longer than <code>min_length</code>.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.CharField</code> or <code>django.db.models.fields.TextField</code>.</p>
|
||||
<p><strong>Signature:</strong> <code>CharField(max_length=None, min_length=None, allow_blank=False)</code></p>
|
||||
<ul>
|
||||
<li><code>max_length</code> - Validates that the input contains no more than this number of characters.</li>
|
||||
<li><code>min_length</code> - Validates that the input contains no fewer than this number of characters.</li>
|
||||
<li><code>allow_blank</code> - If set to <code>True</code> then the empty string should be considered a valid value. If set to <code>False</code> then the empty string is considered invalid and will raise a validation error. Defaults to <code>False</code>.</li>
|
||||
</ul>
|
||||
<p>The <code>allow_null</code> option is also available for string fields, although its usage is discouraged in favor of <code>allow_blank</code>. It is valid to set both <code>allow_blank=True</code> and <code>allow_null=True</code>, but doing so means that there will be two differing types of empty value permissible for string representations, which can lead to data inconsistencies and subtle application bugs.</p>
|
||||
<h2 id="emailfield">EmailField</h2>
|
||||
<p>A text representation, validates the text to be a valid e-mail address.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.EmailField</code></p>
|
||||
<p><strong>Signature:</strong> <code>EmailField(max_length=None, min_length=None, allow_blank=False)</code></p>
|
||||
<h2 id="regexfield">RegexField</h2>
|
||||
<p>A text representation, that validates the given value matches against a certain regular expression.</p>
|
||||
<p>Corresponds to <code>django.forms.fields.RegexField</code>.</p>
|
||||
<p><strong>Signature:</strong> <code>RegexField(regex, max_length=None, min_length=None, allow_blank=False)</code></p>
|
||||
<p>The mandatory <code>regex</code> argument may either be a string, or a compiled python regular expression object.</p>
|
||||
<p>Uses Django's <code>django.core.validators.RegexValidator</code> for validation.</p>
|
||||
<p>Corresponds to <code>django.forms.fields.RegexField</code></p>
|
||||
<p><strong>Signature:</strong> <code>RegexField(regex, max_length=None, min_length=None)</code></p>
|
||||
<h2 id="slugfield">SlugField</h2>
|
||||
<p>A <code>RegexField</code> that validates the input against the pattern <code>[a-zA-Z0-9_-]+</code>.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.SlugField</code>.</p>
|
||||
<p><strong>Signature:</strong> <code>SlugField(max_length=50, min_length=None, allow_blank=False)</code></p>
|
||||
<h2 id="urlfield">URLField</h2>
|
||||
<p>A <code>RegexField</code> that validates the input against a URL matching pattern. Expects fully qualified URLs of the form <code>http://<host>/<path></code>.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.URLField</code>. Uses Django's <code>django.core.validators.URLValidator</code> for validation.</p>
|
||||
<p><strong>Signature:</strong> <code>URLField(max_length=200, min_length=None, allow_blank=False)</code></p>
|
||||
<hr />
|
||||
<h1 id="numeric-fields">Numeric fields</h1>
|
||||
<h2 id="integerfield">IntegerField</h2>
|
||||
<p>An integer representation.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.IntegerField</code>, <code>django.db.models.fields.SmallIntegerField</code>, <code>django.db.models.fields.PositiveIntegerField</code> and <code>django.db.models.fields.PositiveSmallIntegerField</code>.</p>
|
||||
<p><strong>Signature</strong>: <code>IntegerField(max_value=None, min_value=None)</code></p>
|
||||
<ul>
|
||||
<li><code>max_value</code> Validate that the number provided is no greater than this value.</li>
|
||||
<li><code>min_value</code> Validate that the number provided is no less than this value.</li>
|
||||
</ul>
|
||||
<h2 id="floatfield">FloatField</h2>
|
||||
<p>A floating point representation.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.FloatField</code>.</p>
|
||||
<p><strong>Signature</strong>: <code>FloatField(max_value=None, min_value=None)</code></p>
|
||||
<ul>
|
||||
<li><code>max_value</code> Validate that the number provided is no greater than this value.</li>
|
||||
<li><code>min_value</code> Validate that the number provided is no less than this value.</li>
|
||||
</ul>
|
||||
<h2 id="decimalfield">DecimalField</h2>
|
||||
<p>A decimal representation, represented in Python by a <code>Decimal</code> instance.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.DecimalField</code>.</p>
|
||||
<p><strong>Signature</strong>: <code>DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)</code></p>
|
||||
<ul>
|
||||
<li><code>max_digits</code> The maximum number of digits allowed in the number. Note that this number must be greater than or equal to decimal_places.</li>
|
||||
<li><code>decimal_places</code> The number of decimal places to store with the number.</li>
|
||||
<li><code>coerce_to_string</code> Set to <code>True</code> if string values should be returned for the representation, or <code>False</code> if <code>Decimal</code> objects should be returned. Defaults to the same value as the <code>COERCE_DECIMAL_TO_STRING</code> settings key, which will be <code>True</code> unless overridden. If <code>Decimal</code> objects are returned by the serializer, then the final output format will be determined by the renderer.</li>
|
||||
<li><code>max_value</code> Validate that the number provided is no greater than this value.</li>
|
||||
<li><code>min_value</code> Validate that the number provided is no less than this value.</li>
|
||||
</ul>
|
||||
<h4 id="example-usage">Example usage</h4>
|
||||
<p>To validate numbers up to 999 with a resolution of 2 decimal places, you would use:</p>
|
||||
<pre><code>serializers.DecimalField(max_digits=5, decimal_places=2)
|
||||
</code></pre>
|
||||
<p>And to validate numbers up to anything less than one billion with a resolution of 10 decimal places:</p>
|
||||
<pre><code>serializers.DecimalField(max_digits=19, decimal_places=10)
|
||||
</code></pre>
|
||||
<p>This field also takes an optional argument, <code>coerce_to_string</code>. If set to <code>True</code> the representation will be output as a string. If set to <code>False</code> the representation will be left as a <code>Decimal</code> instance and the final representation will be determined by the renderer.</p>
|
||||
<p>If unset, this will default to the same value as the <code>COERCE_DECIMAL_TO_STRING</code> setting, which is <code>True</code> unless set otherwise.</p>
|
||||
<hr />
|
||||
<h1 id="date-and-time-fields">Date and time fields</h1>
|
||||
<h2 id="datetimefield">DateTimeField</h2>
|
||||
<p>A date and time representation.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.DateTimeField</code></p>
|
||||
<p>Corresponds to <code>django.db.models.fields.DateTimeField</code>.</p>
|
||||
<p><strong>Signature:</strong> <code>DateTimeField(format=None, input_formats=None)</code></p>
|
||||
<ul>
|
||||
<li><code>format</code> - A string representing the output format. If not specified, this defaults to the same value as the <code>DATETIME_FORMAT</code> settings key, which will be <code>'iso-8601'</code> unless set. Setting to a format string indicates that <code>to_representation</code> return values should be coerced to string output. Format strings are described below. Setting this value to <code>None</code> indicates that Python <code>datetime</code> objects should be returned by <code>to_representation</code>. In this case the datetime encoding will be determined by the renderer.</li>
|
||||
<li><code>input_formats</code> - A list of strings representing the input formats which may be used to parse the date. If not specified, the <code>DATETIME_INPUT_FORMATS</code> setting will be used, which defaults to <code>['iso-8601']</code>.</li>
|
||||
</ul>
|
||||
<h4 id="datetimefield-format-strings"><code>DateTimeField</code> format strings.</h4>
|
||||
<p>Format strings may either be <a href="http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior">Python strftime formats</a> which explicitly specify the format, or the special string <code>'iso-8601'</code>, which indicates that <a href="http://www.w3.org/TR/NOTE-datetime">ISO 8601</a> style datetimes should be used. (eg <code>'2013-01-29T12:34:56.000000Z'</code>)</p>
|
||||
<p>When a value of <code>None</code> is used for the format <code>datetime</code> objects will be returned by <code>to_representation</code> and the final output representation will determined by the renderer class.</p>
|
||||
<p>In the case of JSON this means the default datetime representation uses the <a href="http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15">ECMA 262 date time string specification</a>. This is a subset of ISO 8601 which uses millisecond precision, and includes the 'Z' suffix for the UTC timezone, for example: <code>2013-01-29T12:34:56.123Z</code>.</p>
|
||||
<h4 id="auto_now-and-auto_now_add-model-fields"><code>auto_now</code> and <code>auto_now_add</code> model fields.</h4>
|
||||
<p>When using <code>ModelSerializer</code> or <code>HyperlinkedModelSerializer</code>, note that any model fields with <code>auto_now=True</code> or <code>auto_now_add=True</code> will use serializer fields that are <code>read_only=True</code> by default.</p>
|
||||
<p>If you want to override this behavior, you'll need to declare the <code>DateTimeField</code> explicitly on the serializer. For example:</p>
|
||||
<pre><code>class CommentSerializer(serializers.ModelSerializer):
|
||||
|
@ -630,84 +725,134 @@ or <code>django.db.models.fields.TextField</code>.</p>
|
|||
class Meta:
|
||||
model = Comment
|
||||
</code></pre>
|
||||
<p>Note that by default, datetime representations are determined by the renderer in use, although this can be explicitly overridden as detailed below.</p>
|
||||
<p>In the case of JSON this means the default datetime representation uses the <a href="http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15">ECMA 262 date time string specification</a>. This is a subset of ISO 8601 which uses millisecond precision, and includes the 'Z' suffix for the UTC timezone, for example: <code>2013-01-29T12:34:56.123Z</code>.</p>
|
||||
<p><strong>Signature:</strong> <code>DateTimeField(format=None, input_formats=None)</code></p>
|
||||
<ul>
|
||||
<li><code>format</code> - A string representing the output format. If not specified, this defaults to <code>None</code>, which indicates that Python <code>datetime</code> objects should be returned by <code>to_native</code>. In this case the datetime encoding will be determined by the renderer.</li>
|
||||
<li><code>input_formats</code> - A list of strings representing the input formats which may be used to parse the date. If not specified, the <code>DATETIME_INPUT_FORMATS</code> setting will be used, which defaults to <code>['iso-8601']</code>.</li>
|
||||
</ul>
|
||||
<p>DateTime format strings may either be <a href="http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior">Python strftime formats</a> which explicitly specify the format, or the special string <code>'iso-8601'</code>, which indicates that <a href="http://www.w3.org/TR/NOTE-datetime">ISO 8601</a> style datetimes should be used. (eg <code>'2013-01-29T12:34:56.000000Z'</code>)</p>
|
||||
<h2 id="datefield">DateField</h2>
|
||||
<p>A date representation.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.DateField</code></p>
|
||||
<p><strong>Signature:</strong> <code>DateField(format=None, input_formats=None)</code></p>
|
||||
<ul>
|
||||
<li><code>format</code> - A string representing the output format. If not specified, this defaults to <code>None</code>, which indicates that Python <code>date</code> objects should be returned by <code>to_native</code>. In this case the date encoding will be determined by the renderer.</li>
|
||||
<li><code>format</code> - A string representing the output format. If not specified, this defaults to the same value as the <code>DATE_FORMAT</code> settings key, which will be <code>'iso-8601'</code> unless set. Setting to a format string indicates that <code>to_representation</code> return values should be coerced to string output. Format strings are described below. Setting this value to <code>None</code> indicates that Python <code>date</code> objects should be returned by <code>to_representation</code>. In this case the date encoding will be determined by the renderer.</li>
|
||||
<li><code>input_formats</code> - A list of strings representing the input formats which may be used to parse the date. If not specified, the <code>DATE_INPUT_FORMATS</code> setting will be used, which defaults to <code>['iso-8601']</code>.</li>
|
||||
</ul>
|
||||
<p>Date format strings may either be <a href="http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior">Python strftime formats</a> which explicitly specify the format, or the special string <code>'iso-8601'</code>, which indicates that <a href="http://www.w3.org/TR/NOTE-datetime">ISO 8601</a> style dates should be used. (eg <code>'2013-01-29'</code>)</p>
|
||||
<h4 id="datefield-format-strings"><code>DateField</code> format strings</h4>
|
||||
<p>Format strings may either be <a href="http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior">Python strftime formats</a> which explicitly specify the format, or the special string <code>'iso-8601'</code>, which indicates that <a href="http://www.w3.org/TR/NOTE-datetime">ISO 8601</a> style dates should be used. (eg <code>'2013-01-29'</code>)</p>
|
||||
<h2 id="timefield">TimeField</h2>
|
||||
<p>A time representation.</p>
|
||||
<p>Optionally takes <code>format</code> as parameter to replace the matching pattern.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.TimeField</code></p>
|
||||
<p><strong>Signature:</strong> <code>TimeField(format=None, input_formats=None)</code></p>
|
||||
<ul>
|
||||
<li><code>format</code> - A string representing the output format. If not specified, this defaults to <code>None</code>, which indicates that Python <code>time</code> objects should be returned by <code>to_native</code>. In this case the time encoding will be determined by the renderer.</li>
|
||||
<li><code>format</code> - A string representing the output format. If not specified, this defaults to the same value as the <code>TIME_FORMAT</code> settings key, which will be <code>'iso-8601'</code> unless set. Setting to a format string indicates that <code>to_representation</code> return values should be coerced to string output. Format strings are described below. Setting this value to <code>None</code> indicates that Python <code>time</code> objects should be returned by <code>to_representation</code>. In this case the time encoding will be determined by the renderer.</li>
|
||||
<li><code>input_formats</code> - A list of strings representing the input formats which may be used to parse the date. If not specified, the <code>TIME_INPUT_FORMATS</code> setting will be used, which defaults to <code>['iso-8601']</code>.</li>
|
||||
</ul>
|
||||
<p>Time format strings may either be <a href="http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior">Python strftime formats</a> which explicitly specify the format, or the special string <code>'iso-8601'</code>, which indicates that <a href="http://www.w3.org/TR/NOTE-datetime">ISO 8601</a> style times should be used. (eg <code>'12:34:56.000000'</code>)</p>
|
||||
<h2 id="integerfield">IntegerField</h2>
|
||||
<p>An integer representation.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.IntegerField</code>, <code>django.db.models.fields.SmallIntegerField</code>, <code>django.db.models.fields.PositiveIntegerField</code> and <code>django.db.models.fields.PositiveSmallIntegerField</code></p>
|
||||
<h2 id="floatfield">FloatField</h2>
|
||||
<p>A floating point representation.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.FloatField</code>.</p>
|
||||
<h2 id="decimalfield">DecimalField</h2>
|
||||
<p>A decimal representation, represented in Python by a Decimal instance.</p>
|
||||
<p>Has two required arguments:</p>
|
||||
<h4 id="timefield-format-strings"><code>TimeField</code> format strings</h4>
|
||||
<p>Format strings may either be <a href="http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior">Python strftime formats</a> which explicitly specify the format, or the special string <code>'iso-8601'</code>, which indicates that <a href="http://www.w3.org/TR/NOTE-datetime">ISO 8601</a> style times should be used. (eg <code>'12:34:56.000000'</code>)</p>
|
||||
<hr />
|
||||
<h1 id="choice-selection-fields">Choice selection fields</h1>
|
||||
<h2 id="choicefield">ChoiceField</h2>
|
||||
<p>A field that can accept a value out of a limited set of choices.</p>
|
||||
<p>Used by <code>ModelSerializer</code> to automatically generate fields if the corresponding model field includes a <code>choices=…</code> argument.</p>
|
||||
<p><strong>Signature:</strong> <code>ChoiceField(choices)</code></p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>max_digits</code> The maximum number of digits allowed in the number. Note that this number must be greater than or equal to decimal_places.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>decimal_places</code> The number of decimal places to store with the number.</p>
|
||||
</li>
|
||||
<li><code>choices</code> - A list of valid values, or a list of <code>(key, display_name)</code> tuples.</li>
|
||||
</ul>
|
||||
<p>For example, to validate numbers up to 999 with a resolution of 2 decimal places, you would use:</p>
|
||||
<pre><code>serializers.DecimalField(max_digits=5, decimal_places=2)
|
||||
</code></pre>
|
||||
<p>And to validate numbers up to anything less than one billion with a resolution of 10 decimal places:</p>
|
||||
<pre><code>serializers.DecimalField(max_digits=19, decimal_places=10)
|
||||
</code></pre>
|
||||
<p>This field also takes an optional argument, <code>coerce_to_string</code>. If set to <code>True</code> the representation will be output as a string. If set to <code>False</code> the representation will be left as a <code>Decimal</code> instance and the final representation will be determined by the renderer.</p>
|
||||
<p>If unset, this will default to the same value as the <code>COERCE_DECIMAL_TO_STRING</code> setting, which is <code>True</code> unless set otherwise.</p>
|
||||
<p><strong>Signature:</strong> <code>DecimalField(max_digits, decimal_places, coerce_to_string=None)</code></p>
|
||||
<p>Corresponds to <code>django.db.models.fields.DecimalField</code>.</p>
|
||||
<h2 id="multiplechoicefield">MultipleChoiceField</h2>
|
||||
<p>A field that can accept a set of zero, one or many values, chosen from a limited set of choices. Takes a single mandatory argument. <code>to_internal_representation</code> returns a <code>set</code> containing the selected values.</p>
|
||||
<p><strong>Signature:</strong> <code>MultipleChoiceField(choices)</code></p>
|
||||
<ul>
|
||||
<li><code>choices</code> - A list of valid values, or a list of <code>(key, display_name)</code> tuples.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h1 id="file-upload-fields">File upload fields</h1>
|
||||
<h4 id="parsers-and-file-uploads">Parsers and file uploads.</h4>
|
||||
<p>The <code>FileField</code> and <code>ImageField</code> classes are only suitable for use with <code>MultiPartParser</code> or <code>FileUploadParser</code>. Most parsers, such as e.g. JSON don't support file uploads.
|
||||
Django's regular <a href="https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS">FILE_UPLOAD_HANDLERS</a> are used for handling uploaded files.</p>
|
||||
<h2 id="filefield">FileField</h2>
|
||||
<p>A file representation. Performs Django's standard FileField validation.</p>
|
||||
<p>Corresponds to <code>django.forms.fields.FileField</code>.</p>
|
||||
<p><strong>Signature:</strong> <code>FileField(max_length=None, allow_empty_file=False)</code></p>
|
||||
<p><strong>Signature:</strong> <code>FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)</code></p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>max_length</code> designates the maximum length for the file name.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>allow_empty_file</code> designates if empty files are allowed.</p>
|
||||
</li>
|
||||
<li><code>max_length</code> - Designates the maximum length for the file name.</li>
|
||||
<li><code>allow_empty_file</code> - Designates if empty files are allowed.</li>
|
||||
<li><code>use_url</code> - If set to <code>True</code> then URL string values will be used for the output representation. If set to <code>False</code> then filename string values will be used for the output representation. Defaults to the value of the <code>UPLOADED_FILES_USE_URL</code> settings key, which is <code>True</code> unless set otherwise.</li>
|
||||
</ul>
|
||||
<h2 id="imagefield">ImageField</h2>
|
||||
<p>An image representation.</p>
|
||||
<p>An image representation. Validates the uploaded file content as matching a known image format.</p>
|
||||
<p>Corresponds to <code>django.forms.fields.ImageField</code>.</p>
|
||||
<p><strong>Signature:</strong> <code>ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)</code></p>
|
||||
<ul>
|
||||
<li><code>max_length</code> - Designates the maximum length for the file name.</li>
|
||||
<li><code>allow_empty_file</code> - Designates if empty files are allowed.</li>
|
||||
<li><code>use_url</code> - If set to <code>True</code> then URL string values will be used for the output representation. If set to <code>False</code> then filename string values will be used for the output representation. Defaults to the value of the <code>UPLOADED_FILES_USE_URL</code> settings key, which is <code>True</code> unless set otherwise.</li>
|
||||
</ul>
|
||||
<p>Requires either the <code>Pillow</code> package or <code>PIL</code> package. The <code>Pillow</code> package is recommended, as <code>PIL</code> is no longer actively maintained.</p>
|
||||
<p>Signature and validation is the same as with <code>FileField</code>.</p>
|
||||
<hr />
|
||||
<p><strong>Note:</strong> <code>FileFields</code> and <code>ImageFields</code> are only suitable for use with MultiPartParser, since e.g. json doesn't support file uploads.
|
||||
Django's regular <a href="https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS">FILE_UPLOAD_HANDLERS</a> are used for handling uploaded files.</p>
|
||||
<h1 id="composite-fields">Composite fields</h1>
|
||||
<h2 id="listfield">ListField</h2>
|
||||
<p>A field class that validates a list of objects.</p>
|
||||
<p><strong>Signature</strong>: <code>ListField(child)</code></p>
|
||||
<ul>
|
||||
<li><code>child</code> - A field instance that should be used for validating the objects in the list.</li>
|
||||
</ul>
|
||||
<p>For example, to validate a list of integers you might use something like the following:</p>
|
||||
<pre><code>scores = serializers.ListField(
|
||||
child=serializers.IntegerField(min_value=0, max_value=100)
|
||||
)
|
||||
</code></pre>
|
||||
<p>The <code>ListField</code> class also supports a declarative style that allows you to write reusable list field classes.</p>
|
||||
<pre><code>class StringListField(serializers.ListField):
|
||||
child = serializers.CharField()
|
||||
</code></pre>
|
||||
<p>We can now reuse our custom <code>StringListField</code> class throughout our application, without having to provide a <code>child</code> argument to it.</p>
|
||||
<hr />
|
||||
<h1 id="miscellaneous-fields">Miscellaneous fields</h1>
|
||||
<h2 id="readonlyfield">ReadOnlyField</h2>
|
||||
<p>A field class that simply returns the value of the field without modification.</p>
|
||||
<p>This field is used by default with <code>ModelSerializer</code> when including field names that relate to an attribute rather than a model field.</p>
|
||||
<p><strong>Signature</strong>: <code>ReadOnlyField()</code></p>
|
||||
<p>For example, is <code>has_expired</code> was a property on the <code>Account</code> model, then the following serializer would automatically generate it as a <code>ReadOnlyField</code>:</p>
|
||||
<pre><code>class AccountSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Account
|
||||
fields = ('id', 'account_name', 'has_expired')
|
||||
</code></pre>
|
||||
<h2 id="hiddenfield">HiddenField</h2>
|
||||
<p>A field class that does not take a value based on user input, but instead takes its value from a default value or callable.</p>
|
||||
<p><strong>Signature</strong>: <code>HiddenField()</code></p>
|
||||
<p>For example, to include a field that always provides the current time as part of the serializer validated data, you would use the following:</p>
|
||||
<pre><code>modified = serializer.HiddenField(default=timezone.now)
|
||||
</code></pre>
|
||||
<p>The <code>HiddenField</code> class is usually only needed if you have some validation that needs to run based on some pre-provided field values, but you do not want to expose all of those fields to the end user.</p>
|
||||
<p>For further examples on <code>HiddenField</code> see the <a href="../validators">validators</a> documentation.</p>
|
||||
<h2 id="modelfield">ModelField</h2>
|
||||
<p>A generic field that can be tied to any arbitrary model field. The <code>ModelField</code> class delegates the task of serialization/deserialization to its associated model field. This field can be used to create serializer fields for custom model fields, without having to create a new custom serializer field.</p>
|
||||
<p>This field is used by <code>ModelSerializer</code> to correspond to custom model field classes.</p>
|
||||
<p><strong>Signature:</strong> <code>ModelField(model_field=<Django ModelField instance>)</code></p>
|
||||
<p>The <code>ModelField</code> class is generally intended for internal use, but can be used by your API if needed. In order to properly instantiate a <code>ModelField</code>, it must be passed a field that is attached to an instantiated model. For example: <code>ModelField(model_field=MyModel()._meta.get_field('custom_field'))</code></p>
|
||||
<h2 id="serializermethodfield">SerializerMethodField</h2>
|
||||
<p>This is a read-only field. It gets its value by calling a method on the serializer class it is attached to. It can be used to add any sort of data to the serialized representation of your object.</p>
|
||||
<p><strong>Signature</strong>: <code>SerializerMethodField(method_name=None)</code></p>
|
||||
<ul>
|
||||
<li><code>method-name</code> - The name of the method on the serializer to be called. If not included this defaults to <code>get_<field_name></code>.</li>
|
||||
</ul>
|
||||
<p>The serializer method referred to by the <code>method_name</code> argument should accept a single argument (in addition to <code>self</code>), which is the object being serialized. It should return whatever you want to be included in the serialized representation of the object. For example:</p>
|
||||
<pre><code>from django.contrib.auth.models import User
|
||||
from django.utils.timezone import now
|
||||
from rest_framework import serializers
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
days_since_joined = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
|
||||
def get_days_since_joined(self, obj):
|
||||
return (now() - obj.date_joined).days
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="custom-fields">Custom fields</h1>
|
||||
<p>If you want to create a custom field, you'll probably want to override either one or both of the <code>.to_native()</code> and <code>.from_native()</code> methods. These two methods are used to convert between the initial datatype, and a primitive, serializable datatype. Primitive datatypes may be any of a number, string, date/time/datetime or None. They may also be any list or dictionary like object that only contains other primitive objects.</p>
|
||||
<p>The <code>.to_native()</code> method is called to convert the initial datatype into a primitive, serializable datatype. The <code>from_native()</code> method is called to restore a primitive datatype into its initial representation.</p>
|
||||
<p>If you want to create a custom field, you'll need to subclass <code>Field</code> and then override either one or both of the <code>.to_representation()</code> and <code>.to_internal_value()</code> methods. These two methods are used to convert between the initial datatype, and a primitive, serializable datatype. Primitive datatypes will typically be any of a number, string, boolean, <code>date</code>/<code>time</code>/<code>datetime</code> or <code>None</code>. They may also be any list or dictionary like object that only contains other primitive objects. Other types might be supported, depending on the renderer that you are using.</p>
|
||||
<p>The <code>.to_representation()</code> method is called to convert the initial datatype into a primitive, serializable datatype.</p>
|
||||
<p>The <code>to_internal_value()</code> method is called to restore a primitive datatype into its internal python representation.</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">Examples</h2>
|
||||
<p>Let's look at an example of serializing a class that represents an RGB color value:</p>
|
||||
<pre><code>class Color(object):
|
||||
|
@ -719,22 +864,27 @@ Django's regular <a href="https://docs.djangoproject.com/en/dev/ref/settings/#st
|
|||
assert(red < 256 and green < 256 and blue < 256)
|
||||
self.red, self.green, self.blue = red, green, blue
|
||||
|
||||
class ColourField(serializers.WritableField):
|
||||
class ColorField(serializers.Field):
|
||||
"""
|
||||
Color objects are serialized into "rgb(#, #, #)" notation.
|
||||
"""
|
||||
def to_native(self, obj):
|
||||
def to_representation(self, obj):
|
||||
return "rgb(%d, %d, %d)" % (obj.red, obj.green, obj.blue)
|
||||
|
||||
def from_native(self, data):
|
||||
def to_internal_value(self, data):
|
||||
data = data.strip('rgb(').rstrip(')')
|
||||
red, green, blue = [int(col) for col in data.split(',')]
|
||||
return Color(red, green, blue)
|
||||
</code></pre>
|
||||
<p>By default field values are treated as mapping to an attribute on the object. If you need to customize how the field value is accessed and set you need to override <code>.field_to_native()</code> and/or <code>.field_from_native()</code>.</p>
|
||||
<p>By default field values are treated as mapping to an attribute on the object. If you need to customize how the field value is accessed and set you need to override <code>.get_attribute()</code> and/or <code>.get_value()</code>.</p>
|
||||
<p>As an example, let's create a field that can be used represent the class name of the object being serialized:</p>
|
||||
<pre><code>class ClassNameField(serializers.Field):
|
||||
def field_to_native(self, obj, field_name):
|
||||
def get_attribute(self, obj):
|
||||
# We pass the object instance onto `to_representation`,
|
||||
# not just the field attribute.
|
||||
return obj
|
||||
|
||||
def to_representation(self, obj):
|
||||
"""
|
||||
Serialize the object's class name.
|
||||
"""
|
||||
|
@ -764,7 +914,7 @@ class ColourField(serializers.WritableField):
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -756,7 +764,7 @@ class ProductFilter(django_filters.FilterSet):
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -432,7 +440,7 @@ def comment_list(request, format=None):
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -488,12 +496,15 @@
|
|||
|
||||
|
||||
|
||||
<h1 id="generic-views">Generic views</h1>
|
||||
<hr />
|
||||
<p><strong>Note</strong>: This is the documentation for the <strong>version 3.0</strong> of REST framework. Documentation for <a href="http://tomchristie.github.io/rest-framework-2-docs/">version 2.4</a> is also available.</p>
|
||||
<hr />
|
||||
<h1 id="generic-views">Generic views</h1>
|
||||
<blockquote>
|
||||
<p>Django’s generic views... were developed as a shortcut for common usage patterns... They take certain common idioms and patterns found in view development and abstract them so that you can quickly write common views of data without having to repeat yourself.</p>
|
||||
<p>— <a href="https://docs.djangoproject.com/en/dev/ref/class-based-views/#base-vs-generic-views">Django Documentation</a></p>
|
||||
</blockquote>
|
||||
<p>One of the key benefits of class based views is the way they allow you to compose bits of reusable behaviour. REST framework takes advantage of this by providing a number of pre-built views that provide for commonly used patterns.</p>
|
||||
<p>One of the key benefits of class based views is the way they allow you to compose bits of reusable behavior. REST framework takes advantage of this by providing a number of pre-built views that provide for commonly used patterns.</p>
|
||||
<p>The generic views provided by REST framework allow you to quickly build API views that map closely to your database models.</p>
|
||||
<p>If the generic views don't suit the needs of your API, you can drop down to using the regular <code>APIView</code> class, or reuse the mixins and base classes used by the generic views to compose your own set of reusable generic views.</p>
|
||||
<h2 id="examples">Examples</h2>
|
||||
|
@ -618,22 +629,23 @@ class UserList(generics.ListCreateAPIView):
|
|||
return 20
|
||||
return 100
|
||||
</code></pre>
|
||||
<p><strong>Save / deletion hooks</strong>:</p>
|
||||
<p>The following methods are provided as placeholder interfaces. They contain empty implementations and are not called directly by <code>GenericAPIView</code>, but they are overridden and used by some of the mixin classes.</p>
|
||||
<p><strong>Save and deletion hooks</strong>:</p>
|
||||
<p>The following methods are provided by the mixin classes, and provide easy overriding of the object save or deletion behavior.</p>
|
||||
<ul>
|
||||
<li><code>pre_save(self, obj)</code> - A hook that is called before saving an object.</li>
|
||||
<li><code>post_save(self, obj, created=False)</code> - A hook that is called after saving an object.</li>
|
||||
<li><code>pre_delete(self, obj)</code> - A hook that is called before deleting an object.</li>
|
||||
<li><code>post_delete(self, obj)</code> - A hook that is called after deleting an object.</li>
|
||||
<li><code>perform_create(self, serializer)</code> - Called by <code>CreateModelMixin</code> when saving a new object instance.</li>
|
||||
<li><code>perform_update(self, serializer)</code> - Called by <code>UpdateModelMixin</code> when saving an existing object instance.</li>
|
||||
<li><code>perform_destroy(self, instance)</code> - Called by <code>DestroyModelMixin</code> when deleting an object instance.</li>
|
||||
</ul>
|
||||
<p>The <code>pre_save</code> method in particular is a useful hook for setting attributes that are implicit in the request, but are not part of the request data. For instance, you might set an attribute on the object based on the request user, or based on a URL keyword argument.</p>
|
||||
<pre><code>def pre_save(self, obj):
|
||||
"""
|
||||
Set the object's owner, based on the incoming request.
|
||||
"""
|
||||
obj.owner = self.request.user
|
||||
<p>These hooks are particularly useful for setting attributes that are implicit in the request, but are not part of the request data. For instance, you might set an attribute on the object based on the request user, or based on a URL keyword argument.</p>
|
||||
<pre><code>def perform_create(self, serializer):
|
||||
serializer.save(user=self.request.user)
|
||||
</code></pre>
|
||||
<p>Remember that the <code>pre_save()</code> method is not called by <code>GenericAPIView</code> itself, but it is called by <code>create()</code> and <code>update()</code> methods on the <code>CreateModelMixin</code> and <code>UpdateModelMixin</code> classes.</p>
|
||||
<p>These override points are also particularly useful for adding behavior that occurs before or after saving an object, such as emailing a confirmation, or logging the update.</p>
|
||||
<pre><code>def perform_update(self, serializer):
|
||||
instance = serializer.save()
|
||||
send_email_confirmation(user=self.request.user, modified=instance)
|
||||
</code></pre>
|
||||
<p><strong>Note</strong>: These methods replace the old-style version 2.x <code>pre_save</code>, <code>post_save</code>, <code>pre_delete</code> and <code>post_delete</code> methods, which are no longer available.</p>
|
||||
<p><strong>Other methods</strong>:</p>
|
||||
<p>You won't typically need to override the following methods, although you might need to call into them if you're writing custom views using <code>GenericAPIView</code>.</p>
|
||||
<ul>
|
||||
|
@ -728,7 +740,7 @@ class UserList(generics.ListCreateAPIView):
|
|||
serializer_class = UserSerializer
|
||||
lookup_fields = ('account', 'username')
|
||||
</code></pre>
|
||||
<p>Using custom mixins is a good option if you have custom behavior that needs to be used</p>
|
||||
<p>Using custom mixins is a good option if you have custom behavior that needs to be used.</p>
|
||||
<h2 id="creating-custom-base-classes">Creating custom base classes</h2>
|
||||
<p>If you are using a mixin across multiple views, you can take this a step further and create your own set of base views that can then be used throughout your project. For example:</p>
|
||||
<pre><code>class BaseRetrieveView(MultipleFieldLookupMixin,
|
||||
|
@ -765,7 +777,7 @@ class BaseRetrieveUpdateDestroyView(MultipleFieldLookupMixin,
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -540,7 +548,7 @@ class CustomPaginationSerializer(pagination.BasePaginationSerializer):
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -449,7 +457,7 @@ sending more complex data than simple forms</p>
|
|||
</blockquote>
|
||||
<p>REST framework includes a number of built in Parser classes, that allow you to accept requests with various media types. There is also support for defining your own custom parsers, which gives you the flexibility to design the media types that your API accepts.</p>
|
||||
<h2 id="how-the-parser-is-determined">How the parser is determined</h2>
|
||||
<p>The set of valid parsers for a view is always defined as a list of classes. When either <code>request.DATA</code> or <code>request.FILES</code> is accessed, REST framework will examine the <code>Content-Type</code> header on the incoming request, and determine which parser to use to parse the request content.</p>
|
||||
<p>The set of valid parsers for a view is always defined as a list of classes. When <code>request.data</code> is accessed, REST framework will examine the <code>Content-Type</code> header on the incoming request, and determine which parser to use to parse the request content.</p>
|
||||
<hr />
|
||||
<p><strong>Note</strong>: When developing client applications always remember to make sure you're setting the <code>Content-Type</code> header when sending data in an HTTP request.</p>
|
||||
<p>If you don't set the content type, most clients will default to using <code>'application/x-www-form-urlencoded'</code>, which may not be what you wanted.</p>
|
||||
|
@ -476,7 +484,7 @@ class ExampleView(APIView):
|
|||
parser_classes = (YAMLParser,)
|
||||
|
||||
def post(self, request, format=None):
|
||||
return Response({'received data': request.DATA})
|
||||
return Response({'received data': request.data})
|
||||
</code></pre>
|
||||
<p>Or, if you're using the <code>@api_view</code> decorator with function based views.</p>
|
||||
<pre><code>@api_view(['POST'])
|
||||
|
@ -485,7 +493,7 @@ def example_view(request, format=None):
|
|||
"""
|
||||
A view that can accept POST requests with YAML content.
|
||||
"""
|
||||
return Response({'received data': request.DATA})
|
||||
return Response({'received data': request.data})
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="api-reference">API Reference</h1>
|
||||
|
@ -503,15 +511,15 @@ def example_view(request, format=None):
|
|||
<p>Requires the <code>defusedxml</code> package to be installed.</p>
|
||||
<p><strong>.media_type</strong>: <code>application/xml</code></p>
|
||||
<h2 id="formparser">FormParser</h2>
|
||||
<p>Parses HTML form content. <code>request.DATA</code> will be populated with a <code>QueryDict</code> of data, <code>request.FILES</code> will be populated with an empty <code>QueryDict</code> of data.</p>
|
||||
<p>Parses HTML form content. <code>request.data</code> will be populated with a <code>QueryDict</code> of data.</p>
|
||||
<p>You will typically want to use both <code>FormParser</code> and <code>MultiPartParser</code> together in order to fully support HTML form data.</p>
|
||||
<p><strong>.media_type</strong>: <code>application/x-www-form-urlencoded</code></p>
|
||||
<h2 id="multipartparser">MultiPartParser</h2>
|
||||
<p>Parses multipart HTML form content, which supports file uploads. Both <code>request.DATA</code> and <code>request.FILES</code> will be populated with a <code>QueryDict</code>.</p>
|
||||
<p>Parses multipart HTML form content, which supports file uploads. Both <code>request.data</code> will be populated with a <code>QueryDict</code>.</p>
|
||||
<p>You will typically want to use both <code>FormParser</code> and <code>MultiPartParser</code> together in order to fully support HTML form data.</p>
|
||||
<p><strong>.media_type</strong>: <code>multipart/form-data</code></p>
|
||||
<h2 id="fileuploadparser">FileUploadParser</h2>
|
||||
<p>Parses raw file upload content. The <code>request.DATA</code> property will be an empty <code>QueryDict</code>, and <code>request.FILES</code> will be a dictionary with a single key <code>'file'</code> containing the uploaded file.</p>
|
||||
<p>Parses raw file upload content. The <code>request.data</code> property will be a dictionary with a single key <code>'file'</code> containing the uploaded file.</p>
|
||||
<p>If the view used with <code>FileUploadParser</code> is called with a <code>filename</code> URL keyword argument, then that argument will be used as the filename. If it is called without a <code>filename</code> URL keyword argument, then the client must set the filename in the <code>Content-Disposition</code> HTTP header. For example <code>Content-Disposition: attachment; filename=upload.jpg</code>.</p>
|
||||
<p><strong>.media_type</strong>: <code>*/*</code></p>
|
||||
<h5 id="notes">Notes:</h5>
|
||||
|
@ -525,7 +533,7 @@ def example_view(request, format=None):
|
|||
parser_classes = (FileUploadParser,)
|
||||
|
||||
def put(self, request, filename, format=None):
|
||||
file_obj = request.FILES['file']
|
||||
file_obj = request.data['file']
|
||||
# ...
|
||||
# do some staff with uploaded file
|
||||
# ...
|
||||
|
@ -534,7 +542,7 @@ def example_view(request, format=None):
|
|||
<hr />
|
||||
<h1 id="custom-parsers">Custom parsers</h1>
|
||||
<p>To implement a custom parser, you should override <code>BaseParser</code>, set the <code>.media_type</code> property, and implement the <code>.parse(self, stream, media_type, parser_context)</code> method.</p>
|
||||
<p>The method should return the data that will be used to populate the <code>request.DATA</code> property.</p>
|
||||
<p>The method should return the data that will be used to populate the <code>request.data</code> property.</p>
|
||||
<p>The arguments passed to <code>.parse()</code> are:</p>
|
||||
<h3 id="stream">stream</h3>
|
||||
<p>A stream-like object representing the body of the request.</p>
|
||||
|
@ -545,7 +553,7 @@ def example_view(request, format=None):
|
|||
<p>Optional. If supplied, this argument will be a dictionary containing any additional context that may be required to parse the request content.</p>
|
||||
<p>By default this will include the following keys: <code>view</code>, <code>request</code>, <code>args</code>, <code>kwargs</code>.</p>
|
||||
<h2 id="example">Example</h2>
|
||||
<p>The following is an example plaintext parser that will populate the <code>request.DATA</code> property with a string representing the body of the request.</p>
|
||||
<p>The following is an example plaintext parser that will populate the <code>request.data</code> property with a string representing the body of the request. </p>
|
||||
<pre><code>class PlainTextParser(BaseParser):
|
||||
"""
|
||||
Plain text parser.
|
||||
|
@ -580,7 +588,7 @@ def parse(self, stream, media_type=None, parser_context=None):
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -632,7 +640,7 @@ class BlacklistPermission(permissions.BasePermission):
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="prev" href="../authentication">
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="prev" href="../validators">
|
||||
Next <i class="icon-arrow-right icon-white"></i>
|
||||
</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="next" href="../fields">
|
||||
|
@ -164,6 +164,10 @@
|
|||
<a href=".">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -341,6 +349,10 @@
|
|||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#inspecting-automatically-generated-relationships">Inspecting automatically generated relationships.</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -350,7 +362,7 @@
|
|||
|
||||
|
||||
<li>
|
||||
<a href="#relatedfield">RelatedField</a>
|
||||
<a href="#stringrelatedfield">StringRelatedField</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
@ -401,6 +413,10 @@
|
|||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#the-queryset-argument">The queryset argument</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#reverse-relations">Reverse relations</a>
|
||||
</li>
|
||||
|
@ -417,10 +433,6 @@
|
|||
<a href="#advanced-hyperlinked-fields">Advanced Hyperlinked fields</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#deprecated-apis">Deprecated APIs</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -452,7 +464,10 @@
|
|||
|
||||
|
||||
|
||||
<h1 id="serializer-relations">Serializer relations</h1>
|
||||
<hr />
|
||||
<p><strong>Note</strong>: This is the documentation for the <strong>version 3.0</strong> of REST framework. Documentation for <a href="http://tomchristie.github.io/rest-framework-2-docs/">version 2.4</a> is also available.</p>
|
||||
<hr />
|
||||
<h1 id="serializer-relations">Serializer relations</h1>
|
||||
<blockquote>
|
||||
<p>Bad programmers worry about the code.
|
||||
Good programmers worry about data structures and their relationships.</p>
|
||||
|
@ -462,6 +477,17 @@ Good programmers worry about data structures and their relationships.</p>
|
|||
<hr />
|
||||
<p><strong>Note:</strong> The relational fields are declared in <code>relations.py</code>, but by convention you should import them from the <code>serializers</code> module, using <code>from rest_framework import serializers</code> and refer to fields as <code>serializers.<FieldName></code>.</p>
|
||||
<hr />
|
||||
<h4 id="inspecting-automatically-generated-relationships">Inspecting automatically generated relationships.</h4>
|
||||
<p>When using the <code>ModelSerializer</code> class, serializer fields and relationships will be automatically generated for you. Inspecting these automatically generated fields can be a useful tool for determining how to customize the relationship style.</p>
|
||||
<p>To do so, open the Django shell, using <code>python manage.py shell</code>, then import the serializer class, instantiate it, and print the object representation…</p>
|
||||
<pre><code>>>> from myapp.serializers import AccountSerializer
|
||||
>>> serializer = AccountSerializer()
|
||||
>>> print repr(serializer) # Or `print(repr(serializer))` in Python 3.x.
|
||||
AccountSerializer():
|
||||
id = IntegerField(label='ID', read_only=True)
|
||||
name = CharField(allow_blank=True, max_length=100, required=False)
|
||||
owner = PrimaryKeyRelatedField(queryset=User.objects.all())
|
||||
</code></pre>
|
||||
<h1 id="api-reference">API Reference</h1>
|
||||
<p>In order to explain the various types of relational fields, we'll use a couple of simple models for our examples. Our models will be for music albums, and the tracks listed on each album.</p>
|
||||
<pre><code>class Album(models.Model):
|
||||
|
@ -481,11 +507,11 @@ class Track(models.Model):
|
|||
def __unicode__(self):
|
||||
return '%d: %s' % (self.order, self.title)
|
||||
</code></pre>
|
||||
<h2 id="relatedfield">RelatedField</h2>
|
||||
<p><code>RelatedField</code> may be used to represent the target of the relationship using its <code>__unicode__</code> method.</p>
|
||||
<h2 id="stringrelatedfield">StringRelatedField</h2>
|
||||
<p><code>StringRelatedField</code> may be used to represent the target of the relationship using its <code>__unicode__</code> method.</p>
|
||||
<p>For example, the following serializer.</p>
|
||||
<pre><code>class AlbumSerializer(serializers.ModelSerializer):
|
||||
tracks = serializers.RelatedField(many=True)
|
||||
tracks = serializers.StringRelatedField(many=True)
|
||||
|
||||
class Meta:
|
||||
model = Album
|
||||
|
@ -533,16 +559,19 @@ class Track(models.Model):
|
|||
<p>By default this field is read-write, although you can change this behavior using the <code>read_only</code> flag.</p>
|
||||
<p><strong>Arguments</strong>:</p>
|
||||
<ul>
|
||||
<li><code>queryset</code> - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set <code>read_only=True</code>.</li>
|
||||
<li><code>many</code> - If applied to a to-many relationship, you should set this argument to <code>True</code>.</li>
|
||||
<li><code>required</code> - If set to <code>False</code>, the field will accept values of <code>None</code> or the empty-string for nullable relationships.</li>
|
||||
<li><code>queryset</code> - By default <code>ModelSerializer</code> classes will use the default queryset for the relationship. <code>Serializer</code> classes must either set a queryset explicitly, or set <code>read_only=True</code>.</li>
|
||||
<li><code>allow_null</code> - If set to <code>True</code>, the field will accept values of <code>None</code> or the empty string for nullable relationships. Defaults to <code>False</code>.</li>
|
||||
</ul>
|
||||
<h2 id="hyperlinkedrelatedfield">HyperlinkedRelatedField</h2>
|
||||
<p><code>HyperlinkedRelatedField</code> may be used to represent the target of the relationship using a hyperlink.</p>
|
||||
<p>For example, the following serializer:</p>
|
||||
<pre><code>class AlbumSerializer(serializers.ModelSerializer):
|
||||
tracks = serializers.HyperlinkedRelatedField(many=True, read_only=True,
|
||||
view_name='track-detail')
|
||||
tracks = serializers.HyperlinkedRelatedField(
|
||||
many=True,
|
||||
read_only=True,
|
||||
view_name='track-detail'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Album
|
||||
|
@ -563,19 +592,23 @@ class Track(models.Model):
|
|||
<p>By default this field is read-write, although you can change this behavior using the <code>read_only</code> flag.</p>
|
||||
<p><strong>Arguments</strong>:</p>
|
||||
<ul>
|
||||
<li><code>view_name</code> - The view name that should be used as the target of the relationship. If you're using <a href="http://www.django-rest-framework.org/api-guide/routers#defaultrouter">the standard router classes</a> this wil be a string with the format <code><modelname>-detail</code>. <strong>required</strong>.</li>
|
||||
<li><code>view_name</code> - The view name that should be used as the target of the relationship. If you're using <a href="http://www.django-rest-framework.org/api-guide/routers#defaultrouter">the standard router classes</a> this will be a string with the format <code><modelname>-detail</code>. <strong>required</strong>.</li>
|
||||
<li><code>queryset</code> - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set <code>read_only=True</code>.</li>
|
||||
<li><code>many</code> - If applied to a to-many relationship, you should set this argument to <code>True</code>.</li>
|
||||
<li><code>required</code> - If set to <code>False</code>, the field will accept values of <code>None</code> or the empty-string for nullable relationships.</li>
|
||||
<li><code>queryset</code> - By default <code>ModelSerializer</code> classes will use the default queryset for the relationship. <code>Serializer</code> classes must either set a queryset explicitly, or set <code>read_only=True</code>.</li>
|
||||
<li><code>allow_null</code> - If set to <code>True</code>, the field will accept values of <code>None</code> or the empty string for nullable relationships. Defaults to <code>False</code>.</li>
|
||||
<li><code>lookup_field</code> - The field on the target that should be used for the lookup. Should correspond to a URL keyword argument on the referenced view. Default is <code>'pk'</code>.</li>
|
||||
<li><code>lookup_url_kwarg</code> - The name of the keyword argument defined in the URL conf that corresponds to the lookup field. Defaults to using the same value as <code>lookup_field</code>.</li>
|
||||
<li><code>format</code> - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the <code>format</code> argument.</li>
|
||||
</ul>
|
||||
<h2 id="slugrelatedfield">SlugRelatedField</h2>
|
||||
<p><code>SlugRelatedField</code> may be used to represent the target of the relationship using a field on the target.</p>
|
||||
<p>For example, the following serializer:</p>
|
||||
<pre><code>class AlbumSerializer(serializers.ModelSerializer):
|
||||
tracks = serializers.SlugRelatedField(many=True, read_only=True,
|
||||
slug_field='title')
|
||||
tracks = serializers.SlugRelatedField(
|
||||
many=True,
|
||||
read_only=True,
|
||||
slug_field='title'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Album
|
||||
|
@ -598,9 +631,9 @@ class Track(models.Model):
|
|||
<p><strong>Arguments</strong>:</p>
|
||||
<ul>
|
||||
<li><code>slug_field</code> - The field on the target that should be used to represent it. This should be a field that uniquely identifies any given instance. For example, <code>username</code>. <strong>required</strong></li>
|
||||
<li><code>queryset</code> - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set <code>read_only=True</code>.</li>
|
||||
<li><code>many</code> - If applied to a to-many relationship, you should set this argument to <code>True</code>.</li>
|
||||
<li><code>required</code> - If set to <code>False</code>, the field will accept values of <code>None</code> or the empty-string for nullable relationships.</li>
|
||||
<li><code>queryset</code> - By default <code>ModelSerializer</code> classes will use the default queryset for the relationship. <code>Serializer</code> classes must either set a queryset explicitly, or set <code>read_only=True</code>.</li>
|
||||
<li><code>allow_null</code> - If set to <code>True</code>, the field will accept values of <code>None</code> or the empty string for nullable relationships. Defaults to <code>False</code>.</li>
|
||||
</ul>
|
||||
<h2 id="hyperlinkedidentityfield">HyperlinkedIdentityField</h2>
|
||||
<p>This field can be applied as an identity relationship, such as the <code>'url'</code> field on a HyperlinkedModelSerializer. It can also be used for an attribute on the object. For example, the following serializer:</p>
|
||||
|
@ -637,7 +670,7 @@ class Track(models.Model):
|
|||
fields = ('order', 'title')
|
||||
|
||||
class AlbumSerializer(serializers.ModelSerializer):
|
||||
tracks = TrackSerializer(many=True)
|
||||
tracks = TrackSerializer(many=True, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Album
|
||||
|
@ -656,14 +689,14 @@ class AlbumSerializer(serializers.ModelSerializer):
|
|||
}
|
||||
</code></pre>
|
||||
<h1 id="custom-relational-fields">Custom relational fields</h1>
|
||||
<p>To implement a custom relational field, you should override <code>RelatedField</code>, and implement the <code>.to_native(self, value)</code> method. This method takes the target of the field as the <code>value</code> argument, and should return the representation that should be used to serialize the target.</p>
|
||||
<p>If you want to implement a read-write relational field, you must also implement the <code>.from_native(self, data)</code> method, and add <code>read_only = False</code> to the class definition.</p>
|
||||
<p>To implement a custom relational field, you should override <code>RelatedField</code>, and implement the <code>.to_representation(self, value)</code> method. This method takes the target of the field as the <code>value</code> argument, and should return the representation that should be used to serialize the target. The <code>value</code> argument will typically be a model instance.</p>
|
||||
<p>If you want to implement a read-write relational field, you must also implement the <code>.to_internal_value(self, data)</code> method.</p>
|
||||
<h2 id="example_1">Example</h2>
|
||||
<p>For, example, we could define a relational field, to serialize a track to a custom string representation, using its ordering, title, and duration.</p>
|
||||
<pre><code>import time
|
||||
|
||||
class TrackListingField(serializers.RelatedField):
|
||||
def to_native(self, value):
|
||||
def to_representation(self, value):
|
||||
duration = time.strftime('%M:%S', time.gmtime(value.duration))
|
||||
return 'Track %d: %s (%s)' % (value.order, value.name, duration)
|
||||
|
||||
|
@ -688,6 +721,11 @@ class AlbumSerializer(serializers.ModelSerializer):
|
|||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="further-notes">Further notes</h1>
|
||||
<h2 id="the-queryset-argument">The <code>queryset</code> argument</h2>
|
||||
<p>The <code>queryset</code> argument is only ever required for <em>writable</em> relationship field, in which case it is used for performing the model instance lookup, that maps from the primitive user input, into a model instance.</p>
|
||||
<p>In version 2.x a serializer class could <em>sometimes</em> automatically determine the <code>queryset</code> argument <em>if</em> a <code>ModelSerializer</code> class was being used.</p>
|
||||
<p>This behavior is now replaced with <em>always</em> using an explicit <code>queryset</code> argument for writable relational fields.</p>
|
||||
<p>Doing so reduces the amount of hidden 'magic' that <code>ModelSerializer</code> provides, makes the behavior of the field more clear, and ensures that it is trivial to move between using the <code>ModelSerializer</code> shortcut, or using fully explicit <code>Serializer</code> classes.</p>
|
||||
<h2 id="reverse-relations">Reverse relations</h2>
|
||||
<p>Note that reverse relationships are not automatically included by the <code>ModelSerializer</code> and <code>HyperlinkedModelSerializer</code> classes. To include a reverse relationship, you must explicitly add it to the fields list. For example:</p>
|
||||
<pre><code>class AlbumSerializer(serializers.ModelSerializer):
|
||||
|
@ -744,7 +782,7 @@ class Note(models.Model):
|
|||
A custom field to use for the `tagged_object` generic relationship.
|
||||
"""
|
||||
|
||||
def to_native(self, value):
|
||||
def to_representation(self, value):
|
||||
"""
|
||||
Serialize tagged objects to a simple textual representation.
|
||||
"""
|
||||
|
@ -754,8 +792,8 @@ class Note(models.Model):
|
|||
return 'Note: ' + value.text
|
||||
raise Exception('Unexpected type of tagged object')
|
||||
</code></pre>
|
||||
<p>If you need the target of the relationship to have a nested representation, you can use the required serializers inside the <code>.to_native()</code> method:</p>
|
||||
<pre><code> def to_native(self, value):
|
||||
<p>If you need the target of the relationship to have a nested representation, you can use the required serializers inside the <code>.to_native()</code> method:</p>
|
||||
<pre><code> def to_representation(self, value):
|
||||
"""
|
||||
Serialize bookmark instances using a bookmark serializer,
|
||||
and note instances using a note serializer.
|
||||
|
@ -800,20 +838,6 @@ attributes are not configured to correctly match the URL conf.</p>
|
|||
return queryset.get(account=account, slug=slug)
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h2 id="deprecated-apis">Deprecated APIs</h2>
|
||||
<p>The following classes have been deprecated, in favor of the <code>many=<bool></code> syntax.
|
||||
They continue to function, but their usage will raise a <code>PendingDeprecationWarning</code>, which is silent by default.</p>
|
||||
<ul>
|
||||
<li><code>ManyRelatedField</code></li>
|
||||
<li><code>ManyPrimaryKeyRelatedField</code></li>
|
||||
<li><code>ManyHyperlinkedRelatedField</code></li>
|
||||
<li><code>ManySlugRelatedField</code></li>
|
||||
</ul>
|
||||
<p>The <code>null=<bool></code> flag has been deprecated in favor of the <code>required=<bool></code> flag. It will continue to function, but will raise a <code>PendingDeprecationWarning</code>.</p>
|
||||
<p>In the 2.3 release, these warnings will be escalated to a <code>DeprecationWarning</code>, which is loud by default.
|
||||
In the 2.4 release, these parts of the API will be removed entirely.</p>
|
||||
<p>For more details see the <a href="../../topics/2.2-announcement">2.2 release announcement</a>.</p>
|
||||
<hr />
|
||||
<h1 id="third-party-packages">Third Party Packages</h1>
|
||||
<p>The following third party packages are also available.</p>
|
||||
<h2 id="drf-nested-routers">DRF Nested Routers</h2>
|
||||
|
@ -832,7 +856,7 @@ In the 2.4 release, these parts of the API will be removed entirely.</p>
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -799,7 +807,7 @@ In this case you can underspecify the media types it should respond to, by using
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -350,15 +358,19 @@
|
|||
|
||||
|
||||
<li>
|
||||
<a href="#data">.DATA</a>
|
||||
<a href="#data">.data</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#files">.FILES</a>
|
||||
<a href="#query_params">.query_params</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#query_params">.QUERY_PARAMS</a>
|
||||
<a href="#data-and-files">.DATA and .FILES</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#query_params_1">.QUERY_PARAMS</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
@ -448,7 +460,10 @@
|
|||
|
||||
|
||||
|
||||
<h1 id="requests">Requests</h1>
|
||||
<hr />
|
||||
<p><strong>Note</strong>: This is the documentation for the <strong>version 3.0</strong> of REST framework. Documentation for <a href="http://tomchristie.github.io/rest-framework-2-docs/">version 2.4</a> is also available.</p>
|
||||
<hr />
|
||||
<h1 id="requests">Requests</h1>
|
||||
<blockquote>
|
||||
<p>If you're doing REST-based web service stuff ... you should ignore request.POST.</p>
|
||||
<p>— Malcom Tredinnick, <a href="https://groups.google.com/d/topic/django-developers/dxI4qVzrBY4/discussion">Django developers group</a></p>
|
||||
|
@ -457,24 +472,26 @@
|
|||
<hr />
|
||||
<h1 id="request-parsing">Request parsing</h1>
|
||||
<p>REST framework's Request objects provide flexible request parsing that allows you to treat requests with JSON data or other media types in the same way that you would normally deal with form data.</p>
|
||||
<h2 id="data">.DATA</h2>
|
||||
<p><code>request.DATA</code> returns the parsed content of the request body. This is similar to the standard <code>request.POST</code> attribute except that:</p>
|
||||
<h2 id="data">.data</h2>
|
||||
<p><code>request.data</code> returns the parsed content of the request body. This is similar to the standard <code>request.POST</code> and <code>request.FILES</code> attributes except that:</p>
|
||||
<ul>
|
||||
<li>It includes all parsed content, including <em>file and non-file</em> inputs.</li>
|
||||
<li>It supports parsing the content of HTTP methods other than <code>POST</code>, meaning that you can access the content of <code>PUT</code> and <code>PATCH</code> requests.</li>
|
||||
<li>It supports REST framework's flexible request parsing, rather than just supporting form data. For example you can handle incoming JSON data in the same way that you handle incoming form data.</li>
|
||||
</ul>
|
||||
<p>For more details see the <a href="../parsers">parsers documentation</a>.</p>
|
||||
<h2 id="files">.FILES</h2>
|
||||
<p><code>request.FILES</code> returns any uploaded files that may be present in the content of the request body. This is the same as the standard <code>HttpRequest</code> behavior, except that the same flexible request parsing is used for <code>request.DATA</code>.</p>
|
||||
<p>For more details see the <a href="../parsers">parsers documentation</a>.</p>
|
||||
<h2 id="query_params">.QUERY_PARAMS</h2>
|
||||
<p><code>request.QUERY_PARAMS</code> is a more correctly named synonym for <code>request.GET</code>.</p>
|
||||
<p>For clarity inside your code, we recommend using <code>request.QUERY_PARAMS</code> instead of the usual <code>request.GET</code>, as <em>any</em> HTTP method type may include query parameters.</p>
|
||||
<h2 id="query_params">.query_params</h2>
|
||||
<p><code>request.query_params</code> is a more correctly named synonym for <code>request.GET</code>.</p>
|
||||
<p>For clarity inside your code, we recommend using <code>request.query_params</code> instead of the Django's standard <code>request.GET</code>. Doing so will help keep your codebase more correct and obvious - any HTTP method type may include query parameters, not just <code>GET</code> requests.</p>
|
||||
<h2 id="data-and-files">.DATA and .FILES</h2>
|
||||
<p>The old-style version 2.x <code>request.data</code> and <code>request.FILES</code> attributes are still available, but are now pending deprecation in favor of the unified <code>request.data</code> attribute.</p>
|
||||
<h2 id="query_params_1">.QUERY_PARAMS</h2>
|
||||
<p>The old-style version 2.x <code>request.QUERY_PARAMS</code> attribute is still available, but is now pending deprecation in favor of the more pythonic <code>request.query_params</code>.</p>
|
||||
<h2 id="parsers">.parsers</h2>
|
||||
<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>Parser</code> instances, based on the <code>parser_classes</code> set on the view or based on the <code>DEFAULT_PARSER_CLASSES</code> setting.</p>
|
||||
<p>You won't typically need to access this property.</p>
|
||||
<hr />
|
||||
<p><strong>Note:</strong> If a client sends malformed content, then accessing <code>request.DATA</code> or <code>request.FILES</code> may raise a <code>ParseError</code>. By default REST framework's <code>APIView</code> class or <code>@api_view</code> decorator will catch the error and return a <code>400 Bad Request</code> response.</p>
|
||||
<p><strong>Note:</strong> If a client sends malformed content, then accessing <code>request.data</code> may raise a <code>ParseError</code>. By default REST framework's <code>APIView</code> class or <code>@api_view</code> decorator will catch the error and return a <code>400 Bad Request</code> response.</p>
|
||||
<p>If a client sends a request with a content-type that cannot be parsed then a <code>UnsupportedMediaType</code> exception will be raised, which by default will be caught and return a <code>415 Unsupported Media Type</code> response.</p>
|
||||
<hr />
|
||||
<h1 id="content-negotiation">Content negotiation</h1>
|
||||
|
@ -537,7 +554,7 @@
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -487,7 +495,7 @@ response['Cache-Control'] = 'no-cache'
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -420,7 +428,7 @@ class APIRootView(APIView):
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -635,7 +643,7 @@ app.router.register_model(MyModel)
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -353,18 +361,26 @@
|
|||
<a href="#deserializing-objects">Deserializing objects</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#saving-instances">Saving instances</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#validation">Validation</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#saving-object-state">Saving object state</a>
|
||||
<a href="#partial-updates">Partial updates</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#dealing-with-nested-objects">Dealing with nested objects</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#writable-nested-representations">Writable nested representations</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#dealing-with-multiple-objects">Dealing with multiple objects</a>
|
||||
</li>
|
||||
|
@ -381,6 +397,10 @@
|
|||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#inspecting-a-modelserializer">Inspecting a ModelSerializer</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#specifying-which-fields-should-be-included">Specifying which fields should be included</a>
|
||||
</li>
|
||||
|
@ -389,16 +409,16 @@
|
|||
<a href="#specifying-nested-serialization">Specifying nested serialization</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#specifying-fields-explicitly">Specifying fields explicitly</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#specifying-which-fields-should-be-read-only">Specifying which fields should be read-only</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#specifying-which-fields-should-be-write-only">Specifying which fields should be write-only</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#specifying-fields-explicitly">Specifying fields explicitly</a>
|
||||
<a href="#specifying-additional-keyword-arguments-for-fields">Specifying additional keyword arguments for fields.</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
@ -422,7 +442,43 @@
|
|||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#overriding-the-url-field-behavior">Overriding the URL field behavior</a>
|
||||
<a href="#changing-the-url-field-name">Changing the URL field name</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="main">
|
||||
<a href="#listserializer">ListSerializer</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#customizing-multiple-create">Customizing multiple create</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#customizing-multiple-update">Customizing multiple update</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="main">
|
||||
<a href="#baseserializer">BaseSerializer</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#read-only-baseserializer-classes">Read-only BaseSerializer classes</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#read-write-baseserializer-classes">Read-write BaseSerializer classes</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#creating-new-base-classes">Creating new base classes</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
@ -433,12 +489,16 @@
|
|||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#overriding-serialization-and-deserialization-behavior">Overriding serialization and deserialization behavior</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#dynamically-modifying-fields">Dynamically modifying fields</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#customising-the-default-fields">Customising the default fields</a>
|
||||
<a href="#customizing-the-default-fields">Customizing the default fields</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
@ -480,7 +540,10 @@
|
|||
|
||||
|
||||
|
||||
<h1 id="serializers">Serializers</h1>
|
||||
<hr />
|
||||
<p><strong>Note</strong>: This is the documentation for the <strong>version 3.0</strong> of REST framework. Documentation for <a href="http://tomchristie.github.io/rest-framework-2-docs/">version 2.4</a> is also available.</p>
|
||||
<hr />
|
||||
<h1 id="serializers">Serializers</h1>
|
||||
<blockquote>
|
||||
<p>Expanding the usefulness of the serializers is something that we would
|
||||
like to address. However, it's not a trivial problem, and it
|
||||
|
@ -488,7 +551,7 @@ will take some serious design work.</p>
|
|||
<p>— Russell Keith-Magee, <a href="https://groups.google.com/d/topic/django-users/sVFaOfQi4wY/discussion">Django users group</a></p>
|
||||
</blockquote>
|
||||
<p>Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into <code>JSON</code>, <code>XML</code> or other content types. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.</p>
|
||||
<p>REST framework's serializers work very similarly to Django's <code>Form</code> and <code>ModelForm</code> classes. It provides a <code>Serializer</code> class which gives you a powerful, generic way to control the output of your responses, as well as a <code>ModelSerializer</code> class which provides a useful shortcut for creating serializers that deal with model instances and querysets.</p>
|
||||
<p>The serializers in REST framework work very similarly to Django's <code>Form</code> and <code>ModelForm</code> classes. We provide a <code>Serializer</code> class which gives you a powerful, generic way to control the output of your responses, as well as a <code>ModelSerializer</code> class which provides a useful shortcut for creating serializers that deal with model instances and querysets.</p>
|
||||
<h2 id="declaring-serializers">Declaring Serializers</h2>
|
||||
<p>Let's start by creating a simple object we can use for example purposes:</p>
|
||||
<pre><code>class Comment(object):
|
||||
|
@ -499,7 +562,7 @@ will take some serious design work.</p>
|
|||
|
||||
comment = Comment(email='leila@example.com', content='foo bar')
|
||||
</code></pre>
|
||||
<p>We'll declare a serializer that we can use to serialize and deserialize <code>Comment</code> objects.</p>
|
||||
<p>We'll declare a serializer that we can use to serialize and deserialize data that corresponds to <code>Comment</code> objects.</p>
|
||||
<p>Declaring a serializer looks very similar to declaring a form:</p>
|
||||
<pre><code>from rest_framework import serializers
|
||||
|
||||
|
@ -507,23 +570,9 @@ class CommentSerializer(serializers.Serializer):
|
|||
email = serializers.EmailField()
|
||||
content = serializers.CharField(max_length=200)
|
||||
created = serializers.DateTimeField()
|
||||
|
||||
def restore_object(self, attrs, instance=None):
|
||||
"""
|
||||
Given a dictionary of deserialized field values, either update
|
||||
an existing model instance, or create a new model instance.
|
||||
"""
|
||||
if instance is not None:
|
||||
instance.email = attrs.get('email', instance.email)
|
||||
instance.content = attrs.get('content', instance.content)
|
||||
instance.created = attrs.get('created', instance.created)
|
||||
return instance
|
||||
return Comment(**attrs)
|
||||
</code></pre>
|
||||
<p>The first part of serializer class defines the fields that get serialized/deserialized. The <code>restore_object</code> method defines how fully fledged instances get created when deserializing data.</p>
|
||||
<p>The <code>restore_object</code> method is optional, and is only required if we want our serializer to support deserialization into fully fledged object instances. If we don't define this method, then deserializing data will simply return a dictionary of items.</p>
|
||||
<h2 id="serializing-objects">Serializing objects</h2>
|
||||
<p>We can now use <code>CommentSerializer</code> to serialize a comment, or list of comments. Again, using the <code>Serializer</code> class looks a lot like using a <code>Form</code> class.</p>
|
||||
<p>We can now use <code>CommentSerializer</code> to serialize a comment, or list of comments. Again, using the <code>Serializer</code> class looks a lot like using a <code>Form</code> class.</p>
|
||||
<pre><code>serializer = CommentSerializer(comment)
|
||||
serializer.data
|
||||
# {'email': u'leila@example.com', 'content': u'foo bar', 'created': datetime.datetime(2012, 8, 22, 16, 20, 9, 822774)}
|
||||
|
@ -535,70 +584,115 @@ json = JSONRenderer().render(serializer.data)
|
|||
json
|
||||
# '{"email": "leila@example.com", "content": "foo bar", "created": "2012-08-22T16:20:09.822"}'
|
||||
</code></pre>
|
||||
<h3 id="customizing-field-representation">Customizing field representation</h3>
|
||||
<p>Sometimes when serializing objects, you may not want to represent everything exactly the way it is in your model.</p>
|
||||
<p>If you need to customize the serialized value of a particular field, you can do this by creating a <code>transform_<fieldname></code> method. For example if you needed to render some markdown from a text field:</p>
|
||||
<pre><code>description = serializers.CharField()
|
||||
description_html = serializers.CharField(source='description', read_only=True)
|
||||
|
||||
def transform_description_html(self, obj, value):
|
||||
from django.contrib.markup.templatetags.markup import markdown
|
||||
return markdown(value)
|
||||
</code></pre>
|
||||
<p>These methods are essentially the reverse of <code>validate_<fieldname></code> (see <em>Validation</em> below.)</p>
|
||||
<h2 id="deserializing-objects">Deserializing objects</h2>
|
||||
<p>Deserialization is similar. First we parse a stream into Python native datatypes...</p>
|
||||
<p>Deserialization is similar. First we parse a stream into Python native datatypes...</p>
|
||||
<pre><code>from StringIO import StringIO
|
||||
from rest_framework.parsers import JSONParser
|
||||
|
||||
stream = StringIO(json)
|
||||
data = JSONParser().parse(stream)
|
||||
</code></pre>
|
||||
<p>...then we restore those native datatypes into a fully populated object instance.</p>
|
||||
<p>...then we restore those native datatypes into a dictionary of validated data.</p>
|
||||
<pre><code>serializer = CommentSerializer(data=data)
|
||||
serializer.is_valid()
|
||||
# True
|
||||
serializer.object
|
||||
# <Comment object at 0x10633b2d0>
|
||||
serializer.validated_data
|
||||
# {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}
|
||||
</code></pre>
|
||||
<p>When deserializing data, we can either create a new instance, or update an existing instance.</p>
|
||||
<pre><code>serializer = CommentSerializer(data=data) # Create new instance
|
||||
serializer = CommentSerializer(comment, data=data) # Update `comment`
|
||||
<h2 id="saving-instances">Saving instances</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>
|
||||
<pre><code>class CommentSerializer(serializers.Serializer):
|
||||
email = serializers.EmailField()
|
||||
content = serializers.CharField(max_length=200)
|
||||
created = serializers.DateTimeField()
|
||||
|
||||
def create(self, validated_data):
|
||||
return Comment(**validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
instance.email = validated_data.get('email', instance.email)
|
||||
instance.content = validated_data.get('content', instance.content)
|
||||
instance.created = validated_data.get('created', instance.created)
|
||||
return instance
|
||||
</code></pre>
|
||||
<p>By default, serializers must be passed values for all required fields or they will throw validation errors. You can use the <code>partial</code> argument in order to allow partial updates.</p>
|
||||
<pre><code>serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True) # Update `comment` with partial data
|
||||
<p>If your object instances correspond to Django models you'll also want to ensure that these methods save the object to the database. For example, if <code>Comment</code> was a Django model, the methods might look like this:</p>
|
||||
<pre><code> def create(self, validated_data):
|
||||
return Comment.objcts.create(**validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
instance.email = validated_data.get('email', instance.email)
|
||||
instance.content = validated_data.get('content', instance.content)
|
||||
instance.created = validated_data.get('created', instance.created)
|
||||
instance.save()
|
||||
return instance
|
||||
</code></pre>
|
||||
<p>Now when deserializing data, we can call <code>.save()</code> to return an object instance, based on the validated data.</p>
|
||||
<pre><code>comment = serializer.save()
|
||||
</code></pre>
|
||||
<p>Calling <code>.save()</code> will either create a new instance, or update an existing instance, depending on if an existing instance was passed when instantiating the serializer class:</p>
|
||||
<pre><code># .save() will create a new instance.
|
||||
serializer = CommentSerializer(data=data)
|
||||
|
||||
# .save() will update the existing `comment` instance.
|
||||
serializer = CommentSerializer(comment, data=data)
|
||||
</code></pre>
|
||||
<p>Both the <code>.create()</code> and <code>.update()</code> methods are optional. You can implement either neither, one, or both of them, depending on the use-case for your serializer class.</p>
|
||||
<h4 id="passing-additional-attributes-to-save">Passing additional attributes to <code>.save()</code></h4>
|
||||
<p>Sometimes you'll want your view code to be able to inject additional data at the point of saving the instance. This additional data might include information like the current user, the current time, or anything else that is not part of the request data.</p>
|
||||
<p>You can do so by including additional keyword arguments when calling <code>.save()</code>. For example:</p>
|
||||
<pre><code>serializer.save(owner=request.user)
|
||||
</code></pre>
|
||||
<p>Any additional keyword arguments will be included in the <code>validated_data</code> argument when <code>.create()</code> or <code>.update()</code> are called.</p>
|
||||
<h4 id="overriding-save-directly">Overriding <code>.save()</code> directly.</h4>
|
||||
<p>In some cases the <code>.create()</code> and <code>.update()</code> method names may not be meaningful. For example, in a contact form we may not be creating new instances, but instead sending an email or other message.</p>
|
||||
<p>In these cases you might instead choose to override <code>.save()</code> directly, as being more readable and meaningful.</p>
|
||||
<p>For example:</p>
|
||||
<pre><code>class ContactForm(serializers.Serializer):
|
||||
email = serializers.EmailField()
|
||||
message = serializers.CharField()
|
||||
|
||||
def save(self):
|
||||
email = self.validated_data['email']
|
||||
message = self.validated_data['message']
|
||||
send_email(from=email, message=message)
|
||||
</code></pre>
|
||||
<p>Note that in the case above we're now having to access the serializer <code>.validated_data</code> property directly.</p>
|
||||
<h2 id="validation">Validation</h2>
|
||||
<p>When deserializing data, you always need to call <code>is_valid()</code> before attempting to access the deserialized object. If any validation errors occur, the <code>.errors</code> property will contain a dictionary representing the resulting error messages. For example:</p>
|
||||
<p>When deserializing data, you always need to call <code>is_valid()</code> before attempting to access the validated data, or save an object instance. If any validation errors occur, the <code>.errors</code> property will contain a dictionary representing the resulting error messages. For example:</p>
|
||||
<pre><code>serializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'})
|
||||
serializer.is_valid()
|
||||
# False
|
||||
serializer.errors
|
||||
# {'email': [u'Enter a valid e-mail address.'], 'created': [u'This field is required.']}
|
||||
</code></pre>
|
||||
<p>Each key in the dictionary will be the field name, and the values will be lists of strings of any error messages corresponding to that field. The <code>non_field_errors</code> key may also be present, and will list any general validation errors.</p>
|
||||
<p>Each key in the dictionary will be the field name, and the values will be lists of strings of any error messages corresponding to that field. The <code>non_field_errors</code> key may also be present, and will list any general validation errors. The name of the <code>non_field_errors</code> key may be customized using the <code>NON_FIELD_ERRORS_KEY</code> REST framework setting.</p>
|
||||
<p>When deserializing a list of items, errors will be returned as a list of dictionaries representing each of the deserialized items.</p>
|
||||
<h4 id="raising-an-exception-on-invalid-data">Raising an exception on invalid data</h4>
|
||||
<p>The <code>.is_valid()</code> method takes an optional <code>raise_exception</code> flag that will cause it to raise a <code>serializers.ValidationError</code> exception if there are validation errors.</p>
|
||||
<p>These exceptions are automatically dealt with by the default exception handler that REST framework provides, and will return <code>HTTP 400 Bad Request</code> responses by default.</p>
|
||||
<pre><code># Return a 400 response if the data was invalid.
|
||||
serializer.is_valid(raise_exception=True)
|
||||
</code></pre>
|
||||
<h4 id="field-level-validation">Field-level validation</h4>
|
||||
<p>You can specify custom field-level validation by adding <code>.validate_<fieldname></code> methods to your <code>Serializer</code> subclass. These are analogous to <code>.clean_<fieldname></code> methods on Django forms, but accept slightly different arguments.</p>
|
||||
<p>They take a dictionary of deserialized attributes as a first argument, and the field name in that dictionary as a second argument (which will be either the name of the field or the value of the <code>source</code> argument to the field, if one was provided).</p>
|
||||
<p>Your <code>validate_<fieldname></code> methods should either just return the <code>attrs</code> dictionary or raise a <code>ValidationError</code>. For example:</p>
|
||||
<p>You can specify custom field-level validation by adding <code>.validate_<field_name></code> methods to your <code>Serializer</code> subclass. These are similar to the <code>.clean_<field_name></code> methods on Django forms.</p>
|
||||
<p>These methods take a single argument, which is the field value that requires validation.</p>
|
||||
<p>Your <code>validate_<field_name></code> methods should return the validated value or raise a <code>serializers.ValidationError</code>. For example:</p>
|
||||
<pre><code>from rest_framework import serializers
|
||||
|
||||
class BlogPostSerializer(serializers.Serializer):
|
||||
title = serializers.CharField(max_length=100)
|
||||
content = serializers.CharField()
|
||||
|
||||
def validate_title(self, attrs, source):
|
||||
def validate_title(self, value):
|
||||
"""
|
||||
Check that the blog post is about Django.
|
||||
"""
|
||||
value = attrs[source]
|
||||
if "django" not in value.lower():
|
||||
if 'django' not in value.lower():
|
||||
raise serializers.ValidationError("Blog post is not about Django")
|
||||
return attrs
|
||||
return value
|
||||
</code></pre>
|
||||
<h4 id="object-level-validation">Object-level validation</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 the <code>attrs</code> dictionary. It should raise a <code>ValidationError</code> if necessary, or just return <code>attrs</code>. 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>ValidationError</code> if necessary, or just return the validated values. For example:</p>
|
||||
<pre><code>from rest_framework import serializers
|
||||
|
||||
class EventSerializer(serializers.Serializer):
|
||||
|
@ -606,21 +700,43 @@ class EventSerializer(serializers.Serializer):
|
|||
start = serializers.DateTimeField()
|
||||
finish = serializers.DateTimeField()
|
||||
|
||||
def validate(self, attrs):
|
||||
def validate(self, data):
|
||||
"""
|
||||
Check that the start is before the stop.
|
||||
"""
|
||||
if attrs['start'] > attrs['finish']:
|
||||
if data['start'] > data['finish']:
|
||||
raise serializers.ValidationError("finish must occur after start")
|
||||
return attrs
|
||||
return data
|
||||
</code></pre>
|
||||
<h2 id="saving-object-state">Saving object state</h2>
|
||||
<p>To save the deserialized objects created by a serializer, call the <code>.save()</code> method:</p>
|
||||
<pre><code>if serializer.is_valid():
|
||||
serializer.save()
|
||||
<h4 id="validators">Validators</h4>
|
||||
<p>Individual fields on a serializer can include validators, by declaring them on the field instance, for example:</p>
|
||||
<pre><code>def multiple_of_ten(value):
|
||||
if value % 10 != 0:
|
||||
raise serializers.ValidationError('Not a multiple of ten')
|
||||
|
||||
class GameRecord(serializers.Serializer):
|
||||
score = IntegerField(validators=[multiple_of_ten])
|
||||
...
|
||||
</code></pre>
|
||||
<p>Serializer classes can also include reusable validators that are applied to the complete set of field data. These validators are included by declaring them on an inner <code>Meta</code> class, like so:</p>
|
||||
<pre><code>class EventSerializer(serializers.Serializer):
|
||||
name = serializers.CharField()
|
||||
room_number = serializers.IntegerField(choices=[101, 102, 103, 201])
|
||||
date = serializers.DateField()
|
||||
|
||||
class Meta:
|
||||
# Each room only has one event per day.
|
||||
validators = UniqueTogetherValidator(
|
||||
queryset=Event.objects.all(),
|
||||
fields=['room_number', 'date']
|
||||
)
|
||||
</code></pre>
|
||||
<p>For more information see the <a href="../validators">validators documentation</a>.</p>
|
||||
<h2 id="partial-updates">Partial updates</h2>
|
||||
<p>By default, serializers must be passed values for all required fields or they will raise validation errors. You can use the <code>partial</code> argument in order to allow partial updates.</p>
|
||||
<pre><code># Update `comment` with partial data
|
||||
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)
|
||||
</code></pre>
|
||||
<p>The default behavior of the method is to simply call <code>.save()</code> on the deserialized object instance. You can override the default save behaviour by overriding the <code>.save_object(obj)</code> method on the serializer class.</p>
|
||||
<p>The generic views provided by REST framework call the <code>.save()</code> method when updating or creating entities.</p>
|
||||
<h2 id="dealing-with-nested-objects">Dealing with nested objects</h2>
|
||||
<p>The previous examples are fine for dealing with objects that only have simple datatypes, but sometimes we also need to be able to represent more complex objects, where some of the attributes of an object might not be simple datatypes such as strings, dates or integers.</p>
|
||||
<p>The <code>Serializer</code> class is itself a type of <code>Field</code>, and can be used to represent relationships where one object type is nested inside another.</p>
|
||||
|
@ -646,13 +762,92 @@ class CommentSerializer(serializers.Serializer):
|
|||
content = serializers.CharField(max_length=200)
|
||||
created = serializers.DateTimeField()
|
||||
</code></pre>
|
||||
<p>Validation of nested objects will work the same as before. Errors with nested objects will be nested under the field name of the nested object.</p>
|
||||
<h2 id="writable-nested-representations">Writable nested representations</h2>
|
||||
<p>When dealing with nested representations that support deserializing the data, an errors with nested objects will be nested under the field name of the nested object.</p>
|
||||
<pre><code>serializer = CommentSerializer(data={'user': {'email': 'foobar', 'username': 'doe'}, 'content': 'baz'})
|
||||
serializer.is_valid()
|
||||
# False
|
||||
serializer.errors
|
||||
# {'user': {'email': [u'Enter a valid e-mail address.']}, 'created': [u'This field is required.']}
|
||||
</code></pre>
|
||||
<p>Similarly, the <code>.validated_data</code> property will include nested data structures.</p>
|
||||
<h4 id="writing-create-methods-for-nested-representations">Writing <code>.create()</code> methods for nested representations</h4>
|
||||
<p>If you're supporting writable nested representations you'll need to write <code>.create()</code> or <code>.update()</code> methods that handle saving multiple objects.</p>
|
||||
<p>The following example demonstrates how you might handle creating a user with a nested profile object.</p>
|
||||
<pre><code>class UserSerializer(serializers.ModelSerializer):
|
||||
profile = ProfileSerializer()
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ('username', 'email', 'profile')
|
||||
|
||||
def create(self, validated_data):
|
||||
profile_data = validated_data.pop('profile')
|
||||
user = User.objects.create(**validated_data)
|
||||
Profile.objects.create(user=user, **profile_data)
|
||||
return user
|
||||
</code></pre>
|
||||
<h4 id="writing-update-methods-for-nested-representations">Writing <code>.update()</code> methods for nested representations</h4>
|
||||
<p>For updates you'll want to think carefully about how to handle updates to relationships. For example if the data for the relationship is <code>None</code>, or not provided, which of the following should occur?</p>
|
||||
<ul>
|
||||
<li>Set the relationship to <code>NULL</code> in the database.</li>
|
||||
<li>Delete the associated instance.</li>
|
||||
<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>
|
||||
<pre><code> def update(self, instance, validated_data):
|
||||
profile_data = validated_data.pop('profile')
|
||||
# Unless the application properly enforces that this field is
|
||||
# always set, the follow could raise a `DoesNotExist`, which
|
||||
# would need to be handled.
|
||||
profile = instance.profile
|
||||
|
||||
user.username = validated_data.get('username', instance.username)
|
||||
user.email = validated_data.get('email', instance.email)
|
||||
user.save()
|
||||
|
||||
profile.is_premium_member = profile_data.get(
|
||||
'is_premium_member',
|
||||
profile.is_premium_member
|
||||
)
|
||||
profile.has_support_contract = profile_data.get(
|
||||
'has_support_contract',
|
||||
profile.has_support_contract
|
||||
)
|
||||
profile.save()
|
||||
|
||||
return user
|
||||
</code></pre>
|
||||
<p>Because the behavior of nested creates and updates can be ambiguous, and may require complex dependancies between related models, REST framework 3 requires you to always write these methods explicitly. The default <code>ModelSerializer</code> <code>.create()</code> and <code>.update()</code> methods do not include support for writable nested representations.</p>
|
||||
<p>It is possible that a third party package, providing automatic support some kinds of automatic writable nested representations may be released alongside the 3.1 release.</p>
|
||||
<h4 id="handling-saving-related-instances-in-model-manager-classes">Handling saving related instances in model manager classes</h4>
|
||||
<p>An alternative to saving multiple related instances in the serializer is to write custom model manager classes handle creating the correct instances.</p>
|
||||
<p>For example, suppose we wanted to ensure that <code>User</code> instances and <code>Profile</code> instances are always created together as a pair. We might write a custom manager class that looks something like this:</p>
|
||||
<pre><code>class UserManager(models.Manager):
|
||||
...
|
||||
|
||||
def create(self, username, email, is_premium_member=False, has_support_contract=False):
|
||||
user = User(username=username, email=email)
|
||||
user.save()
|
||||
profile = Profile(
|
||||
user=user,
|
||||
is_premium_member=is_premium_member,
|
||||
has_support_contract=has_support_contract
|
||||
)
|
||||
profile.save()
|
||||
return user
|
||||
</code></pre>
|
||||
<p>This manager class now more nicely encapsulates that user instances and profile instances are always created at the same time. Our <code>.create()</code> method on the serializer class can now be re-written to use the new manager method.</p>
|
||||
<pre><code>def create(self, validated_data):
|
||||
return User.objects.create(
|
||||
username=validated_data['username'],
|
||||
email=validated_data['email']
|
||||
is_premium_member=validated_data['profile']['is_premium_member']
|
||||
has_support_contract=validated_data['profile']['has_support_contract']
|
||||
)
|
||||
</code></pre>
|
||||
<p>For more details on this approach see the Django documentation on <a href="../../model-managers">model managers</a>, and <a href="../../encapsulation-blogpost">this blogpost on using model and manger classes</a>.</p>
|
||||
<h2 id="dealing-with-multiple-objects">Dealing with multiple objects</h2>
|
||||
<p>The <code>Serializer</code> class can also handle serializing or deserializing lists of objects.</p>
|
||||
<h4 id="serializing-multiple-objects">Serializing multiple objects</h4>
|
||||
|
@ -666,65 +861,8 @@ serializer.data
|
|||
# {'id': 2, 'title': 'The wind-up bird chronicle', 'author': 'Haruki Murakami'}
|
||||
# ]
|
||||
</code></pre>
|
||||
<h4 id="deserializing-multiple-objects-for-creation">Deserializing multiple objects for creation</h4>
|
||||
<p>To deserialize a list of object data, and create multiple object instances in a single pass, you should also set the <code>many=True</code> flag, and pass a list of data to be deserialized.</p>
|
||||
<p>This allows you to write views that create multiple items when a <code>POST</code> request is made.</p>
|
||||
<p>For example:</p>
|
||||
<pre><code>data = [
|
||||
{'title': 'The bell jar', 'author': 'Sylvia Plath'},
|
||||
{'title': 'For whom the bell tolls', 'author': 'Ernest Hemingway'}
|
||||
]
|
||||
serializer = BookSerializer(data=data, many=True)
|
||||
serializer.is_valid()
|
||||
# True
|
||||
serializer.save() # `.save()` will be called on each deserialized instance
|
||||
</code></pre>
|
||||
<h4 id="deserializing-multiple-objects-for-update">Deserializing multiple objects for update</h4>
|
||||
<p>You can also deserialize a list of objects as part of a bulk update of multiple existing items.
|
||||
In this case you need to supply both an existing list or queryset of items, as well as a list of data to update those items with.</p>
|
||||
<p>This allows you to write views that update or create multiple items when a <code>PUT</code> request is made.</p>
|
||||
<pre><code># Capitalizing the titles of the books
|
||||
queryset = Book.objects.all()
|
||||
data = [
|
||||
{'id': 3, 'title': 'The Bell Jar', 'author': 'Sylvia Plath'},
|
||||
{'id': 4, 'title': 'For Whom the Bell Tolls', 'author': 'Ernest Hemingway'}
|
||||
]
|
||||
serializer = BookSerializer(queryset, data=data, many=True)
|
||||
serializer.is_valid()
|
||||
# True
|
||||
serializer.save() # `.save()` will be called on each updated or newly created instance.
|
||||
</code></pre>
|
||||
<p>By default bulk updates will be limited to updating instances that already exist in the provided queryset.</p>
|
||||
<p>When performing a bulk update you may want to allow new items to be created, and missing items to be deleted. To do so, pass <code>allow_add_remove=True</code> to the serializer.</p>
|
||||
<pre><code>serializer = BookSerializer(queryset, data=data, many=True, allow_add_remove=True)
|
||||
serializer.is_valid()
|
||||
# True
|
||||
serializer.save() # `.save()` will be called on updated or newly created instances.
|
||||
# `.delete()` will be called on any other items in the `queryset`.
|
||||
</code></pre>
|
||||
<p>Passing <code>allow_add_remove=True</code> ensures that any update operations will completely overwrite the existing queryset, rather than simply updating existing objects.</p>
|
||||
<h4 id="how-identity-is-determined-when-performing-bulk-updates">How identity is determined when performing bulk updates</h4>
|
||||
<p>Performing a bulk update is slightly more complicated than performing a bulk creation, because the serializer needs a way to determine how the items in the incoming data should be matched against the existing object instances.</p>
|
||||
<p>By default the serializer class will use the <code>id</code> key on the incoming data to determine the canonical identity of an object. If you need to change this behavior you should override the <code>get_identity</code> method on the <code>Serializer</code> class. For example:</p>
|
||||
<pre><code>class AccountSerializer(serializers.Serializer):
|
||||
slug = serializers.CharField(max_length=100)
|
||||
created = serializers.DateTimeField()
|
||||
... # Various other fields
|
||||
|
||||
def get_identity(self, data):
|
||||
"""
|
||||
This hook is required for bulk update.
|
||||
We need to override the default, to use the slug as the identity.
|
||||
|
||||
Note that the data has not yet been validated at this point,
|
||||
so we need to deal gracefully with incorrect datatypes.
|
||||
"""
|
||||
try:
|
||||
return data.get('slug', None)
|
||||
except AttributeError:
|
||||
return None
|
||||
</code></pre>
|
||||
<p>To map the incoming data items to their corresponding object instances, the <code>.get_identity()</code> method will be called both against the incoming data, and against the serialized representation of the existing objects.</p>
|
||||
<h4 id="deserializing-multiple-objects">Deserializing multiple objects</h4>
|
||||
<p>The default behavior for deserializing multiple objects is to support multiple object creation, but not support multiple object updates. For more information on how to support or customize either of these cases, see the <a href="#ListSerializer">ListSerializer</a> documentation below.</p>
|
||||
<h2 id="including-extra-context">Including extra context</h2>
|
||||
<p>There are some cases where you need to provide extra context to the serializer in addition to the object being serialized. One common case is if you're using a serializer that includes hyperlinked relations, which requires the serializer to have access to the current request so that it can properly generate fully qualified URLs.</p>
|
||||
<p>You can provide arbitrary additional context by passing a <code>context</code> argument when instantiating the serializer. For example:</p>
|
||||
|
@ -732,20 +870,35 @@ serializer.save() # `.save()` will be called on updated or newly created instan
|
|||
serializer.data
|
||||
# {'id': 6, 'owner': u'denvercoder9', 'created': datetime.datetime(2013, 2, 12, 09, 44, 56, 678870), 'details': 'http://example.com/accounts/6/details'}
|
||||
</code></pre>
|
||||
<p>The context dictionary can be used within any serializer field logic, such as a custom <code>.to_native()</code> method, by accessing the <code>self.context</code> attribute.</p>
|
||||
<p>-</p>
|
||||
<p>The context dictionary can be used within any serializer field logic, such as a custom <code>.to_representation()</code> method, by accessing the <code>self.context</code> attribute.</p>
|
||||
<hr />
|
||||
<h1 id="modelserializer">ModelSerializer</h1>
|
||||
<p>Often you'll want serializer classes that map closely to model definitions.
|
||||
The <code>ModelSerializer</code> class lets you automatically create a Serializer class with fields that correspond to the Model fields.</p>
|
||||
<p>Often you'll want serializer classes that map closely to Django model definitions.</p>
|
||||
<p>The <code>ModelSerializer</code> class provides a shortcut that lets you automatically create a <code>Serializer</code> class with fields that correspond to the Model fields.</p>
|
||||
<p><strong>The <code>ModelSerializer</code> class is the same as a regular <code>Serializer</code> class, except that</strong>:</p>
|
||||
<ul>
|
||||
<li>It will automatically generate a set of fields for you, based on the model.</li>
|
||||
<li>It will automatically generate validators for the serializer, such as unique_together validators.</li>
|
||||
<li>It includes simple default implementations of <code>.create()</code> and <code>.update()</code>.</li>
|
||||
</ul>
|
||||
<p>Declaring a <code>ModelSerializer</code> looks like this:</p>
|
||||
<pre><code>class AccountSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Account
|
||||
</code></pre>
|
||||
<p>By default, all the model fields on the class will be mapped to corresponding serializer fields.</p>
|
||||
<p>Any relationships such as foreign keys on the model will be mapped to <code>PrimaryKeyRelatedField</code>. Other models fields will be mapped to a corresponding serializer field.</p>
|
||||
<hr />
|
||||
<p><strong>Note</strong>: When validation is applied to a <code>ModelSerializer</code>, both the serializer fields, and their corresponding model fields must correctly validate. If you have optional fields on your model, make sure to correctly set <code>blank=True</code> on the model field, as well as setting <code>required=False</code> on the serializer field.</p>
|
||||
<hr />
|
||||
<p>By default, all the model fields on the class will be mapped to a corresponding serializer fields.</p>
|
||||
<p>Any relationships such as foreign keys on the model will be mapped to <code>PrimaryKeyRelatedField</code>. Reverse relationships are not included by default unless explicitly included as described below.</p>
|
||||
<h4 id="inspecting-a-modelserializer">Inspecting a <code>ModelSerializer</code></h4>
|
||||
<p>Serializer classes generate helpful verbose representation strings, that allow you to fully inspect the state of their fields. This is particularly useful when working with <code>ModelSerializers</code> where you want to determine what set of fields and validators are being automatically created for you.</p>
|
||||
<p>To do so, open the Django shell, using <code>python manage.py shell</code>, then import the serializer class, instantiate it, and print the object representation…</p>
|
||||
<pre><code>>>> from myapp.serializers import AccountSerializer
|
||||
>>> serializer = AccountSerializer()
|
||||
>>> print repr(serializer) # Or `print(repr(serializer))` in Python 3.x.
|
||||
AccountSerializer():
|
||||
id = IntegerField(label='ID', read_only=True)
|
||||
name = CharField(allow_blank=True, max_length=100, required=False)
|
||||
owner = PrimaryKeyRelatedField(queryset=User.objects.all())
|
||||
</code></pre>
|
||||
<h2 id="specifying-which-fields-should-be-included">Specifying which fields should be included</h2>
|
||||
<p>If you only want a subset of the default fields to be used in a model serializer, you can do so using <code>fields</code> or <code>exclude</code> options, just as you would with a <code>ModelForm</code>.</p>
|
||||
<p>For example:</p>
|
||||
|
@ -754,6 +907,8 @@ The <code>ModelSerializer</code> class lets you automatically create a Serialize
|
|||
model = Account
|
||||
fields = ('id', 'account_name', 'users', 'created')
|
||||
</code></pre>
|
||||
<p>The names in the <code>fields</code> option 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>
|
||||
<h2 id="specifying-nested-serialization">Specifying nested serialization</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):
|
||||
|
@ -764,32 +919,6 @@ The <code>ModelSerializer</code> class lets you automatically create a Serialize
|
|||
</code></pre>
|
||||
<p>The <code>depth</code> option should be set to an integer value that indicates the depth of relationships that should be traversed before reverting to a flat representation.</p>
|
||||
<p>If you want to customize the way the serialization is done (e.g. using <code>allow_add_remove</code>) you'll need to define the field yourself.</p>
|
||||
<h2 id="specifying-which-fields-should-be-read-only">Specifying which fields should be read-only</h2>
|
||||
<p>You may wish to specify multiple fields as read-only. Instead of adding each field explicitly with the <code>read_only=True</code> attribute, you may use the <code>read_only_fields</code> Meta option, like so:</p>
|
||||
<pre><code>class AccountSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Account
|
||||
fields = ('id', 'account_name', 'users', 'created')
|
||||
read_only_fields = ('account_name',)
|
||||
</code></pre>
|
||||
<p>Model fields which have <code>editable=False</code> set, and <code>AutoField</code> fields will be set to read-only by default, and do not need to be added to the <code>read_only_fields</code> option.</p>
|
||||
<h2 id="specifying-which-fields-should-be-write-only">Specifying which fields should be write-only</h2>
|
||||
<p>You may wish to specify multiple fields as write-only. Instead of adding each field explicitly with the <code>write_only=True</code> attribute, you may use the <code>write_only_fields</code> Meta option, like so:</p>
|
||||
<pre><code>class CreateUserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ('email', 'username', 'password')
|
||||
write_only_fields = ('password',) # Note: Password field is write-only
|
||||
|
||||
def restore_object(self, attrs, instance=None):
|
||||
"""
|
||||
Instantiate a new User instance.
|
||||
"""
|
||||
assert instance is None, 'Cannot update users with CreateUserSerializer'
|
||||
user = User(email=attrs['email'], username=attrs['username'])
|
||||
user.set_password(attrs['password'])
|
||||
return user
|
||||
</code></pre>
|
||||
<h2 id="specifying-fields-explicitly">Specifying fields explicitly</h2>
|
||||
<p>You can add extra fields to a <code>ModelSerializer</code> or override the default fields by declaring fields on the class, just as you would for a <code>Serializer</code> class.</p>
|
||||
<pre><code>class AccountSerializer(serializers.ModelSerializer):
|
||||
|
@ -800,12 +929,40 @@ The <code>ModelSerializer</code> class lets you automatically create a Serialize
|
|||
model = Account
|
||||
</code></pre>
|
||||
<p>Extra fields can correspond to any property or callable on the model.</p>
|
||||
<h2 id="specifying-which-fields-should-be-read-only">Specifying which fields should be read-only</h2>
|
||||
<p>You may wish to specify multiple fields as read-only. Instead of adding each field explicitly with the <code>read_only=True</code> attribute, you may use the shortcut Meta option, <code>read_only_fields</code>.</p>
|
||||
<p>This option should be a list or tuple of field names, and is declared as follows:</p>
|
||||
<pre><code>class AccountSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Account
|
||||
fields = ('id', 'account_name', 'users', 'created')
|
||||
read_only_fields = ('account_name',)
|
||||
</code></pre>
|
||||
<p>Model fields which have <code>editable=False</code> set, and <code>AutoField</code> fields will be set to read-only by default, and do not need to be added to the <code>read_only_fields</code> option.</p>
|
||||
<h2 id="specifying-additional-keyword-arguments-for-fields">Specifying additional keyword arguments for fields.</h2>
|
||||
<p>There is also a shortcut allowing you to specify arbitrary additional keyword arguments on fields, using the <code>extra_kwargs</code> option. Similarly to <code>read_only_fields</code> this means you do not need to explicitly declare the field on the serializer.</p>
|
||||
<p>This option is a dictionary, mapping field names to a dictionary of keyword arguments. For example:</p>
|
||||
<pre><code>class CreateUserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ('email', 'username', 'password')
|
||||
extra_kwargs = {'password': {'write_only': True}}
|
||||
|
||||
def create(self, validated_data):
|
||||
user = User(
|
||||
email=validated_data['email'],
|
||||
username=validated_data['username']
|
||||
)
|
||||
user.set_password(validated_data['password'])
|
||||
user.save()
|
||||
return user
|
||||
</code></pre>
|
||||
<h2 id="relational-fields">Relational fields</h2>
|
||||
<p>When serializing model instances, there are a number of different ways you might choose to represent relationships. The default representation for <code>ModelSerializer</code> is to use the primary keys of the related instances.</p>
|
||||
<p>Alternative representations include serializing using hyperlinks, serializing complete nested representations, or serializing with a custom representation.</p>
|
||||
<p>For full details see the <a href="../relations">serializer relations</a> documentation.</p>
|
||||
<h2 id="inheritance-of-the-meta-class">Inheritance of the 'Meta' class</h2>
|
||||
<p>The inner <code>Meta</code> class on serializers is not inherited from parent classes by default. This is the same behaviour as with Django's <code>Model</code> and <code>ModelForm</code> classes. If you want the <code>Meta</code> class to inherit from a parent class you must do so explicitly. For example:</p>
|
||||
<p>The inner <code>Meta</code> class on serializers is not inherited from parent classes by default. This is the same behavior as with Django's <code>Model</code> and <code>ModelForm</code> classes. If you want the <code>Meta</code> class to inherit from a parent class you must do so explicitly. For example:</p>
|
||||
<pre><code>class AccountSerializer(MyBaseSerializer):
|
||||
class Meta(MyBaseSerializer.Meta):
|
||||
model = Account
|
||||
|
@ -825,19 +982,21 @@ The <code>ModelSerializer</code> class lets you automatically create a Serialize
|
|||
<h2 id="how-hyperlinked-views-are-determined">How hyperlinked views are determined</h2>
|
||||
<p>There needs to be a way of determining which views should be used for hyperlinking to model instances.</p>
|
||||
<p>By default hyperlinks are expected to correspond to a view name that matches the style <code>'{model_name}-detail'</code>, and looks up the instance by a <code>pk</code> keyword argument.</p>
|
||||
<p>You can change the field that is used for object lookups by setting the <code>lookup_field</code> option. The value of this option should correspond both with a kwarg in the URL conf, and with a field on the model. For example:</p>
|
||||
<p>You can override a URL field view name and lookup field by using either, or both of, the <code>view_name</code> and <code>lookup_field</code> options in the <code>extra_field_kwargs</code> setting, like so:</p>
|
||||
<pre><code>class AccountSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = Account
|
||||
fields = ('url', 'account_name', 'users', 'created')
|
||||
lookup_field = 'slug'
|
||||
fields = ('account_url', 'account_name', 'users', 'created')
|
||||
extra_field_kwargs = {
|
||||
'url': {'view_name': 'accounts', 'lookup_field': 'account_name'}
|
||||
'users': {'lookup_field': 'username'}
|
||||
}
|
||||
</code></pre>
|
||||
<p>Note that the <code>lookup_field</code> will be used as the default on <em>all</em> hyperlinked fields, including both the URL identity, and any hyperlinked relationships.</p>
|
||||
<p>For more specific requirements such as specifying a different lookup for each field, you'll want to set the fields on the serializer explicitly. For example:</p>
|
||||
<p>Alternatively you can set the fields on the serializer explicitly. For example:</p>
|
||||
<pre><code>class AccountSerializer(serializers.HyperlinkedModelSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(
|
||||
view_name='account_detail',
|
||||
lookup_field='account_name'
|
||||
view_name='accounts',
|
||||
lookup_field='slug'
|
||||
)
|
||||
users = serializers.HyperlinkedRelatedField(
|
||||
view_name='user-detail',
|
||||
|
@ -850,28 +1009,221 @@ The <code>ModelSerializer</code> class lets you automatically create a Serialize
|
|||
model = Account
|
||||
fields = ('url', 'account_name', 'users', 'created')
|
||||
</code></pre>
|
||||
<h2 id="overriding-the-url-field-behavior">Overriding the URL field behavior</h2>
|
||||
<hr />
|
||||
<p><strong>Tip</strong>: Properly matching together hyperlinked representations and your URL conf can sometimes be a bit fiddly. Printing the <code>repr</code> of a <code>HyperlinkedModelSerializer</code> instance is a particularly useful way to inspect exactly which view names and lookup fields the relationships are expected to map too.</p>
|
||||
<hr />
|
||||
<h2 id="changing-the-url-field-name">Changing the URL field name</h2>
|
||||
<p>The name of the URL field defaults to 'url'. You can override this globally, by using the <code>URL_FIELD_NAME</code> setting.</p>
|
||||
<p>You can also override this on a per-serializer basis by using the <code>url_field_name</code> option on the serializer, like so:</p>
|
||||
<pre><code>class AccountSerializer(serializers.HyperlinkedModelSerializer):
|
||||
<hr />
|
||||
<h1 id="listserializer">ListSerializer</h1>
|
||||
<p>The <code>ListSerializer</code> class provides the behavior for serializing and validating multiple objects at once. You won't <em>typically</em> need to use <code>ListSerializer</code> directly, but should instead simply pass <code>many=True</code> when instantiating a serializer.</p>
|
||||
<p>When a serializer is instantiated and <code>many=True</code> is passed, a <code>ListSerializer</code> instance will be created. The serializer class then becomes a child of the parent <code>ListSerializer</code></p>
|
||||
<p>There <em>are</em> a few use cases when you might want to customize the <code>ListSerializer</code> behavior. For example:</p>
|
||||
<ul>
|
||||
<li>You want to provide particular validation of the lists, such as always ensuring that there is at least one element in a list.</li>
|
||||
<li>You want to customize the create or update behavior of multiple objects.</li>
|
||||
</ul>
|
||||
<p>For these cases you can modify the class that is used when <code>many=True</code> is passed, by using the <code>list_serializer_class</code> option on the serializer <code>Meta</code> class.</p>
|
||||
<p>For example:</p>
|
||||
<pre><code>class CustomListSerializer(serializers.ListSerializer):
|
||||
...
|
||||
|
||||
class CustomSerializer(serializers.Serializer):
|
||||
...
|
||||
class Meta:
|
||||
model = Account
|
||||
fields = ('account_url', 'account_name', 'users', 'created')
|
||||
url_field_name = 'account_url'
|
||||
list_serializer_class = CustomListSerializer
|
||||
</code></pre>
|
||||
<p><strong>Note</strong>: The generic view implementations normally generate a <code>Location</code> header in response to successful <code>POST</code> requests. Serializers using <code>url_field_name</code> option will not have this header automatically included by the view. If you need to do so you will ned to also override the view's <code>get_success_headers()</code> method.</p>
|
||||
<p>You can also override the URL field's view name and lookup field without overriding the field explicitly, by using the <code>view_name</code> and <code>lookup_field</code> options, like so:</p>
|
||||
<pre><code>class AccountSerializer(serializers.HyperlinkedModelSerializer):
|
||||
<h4 id="customizing-multiple-create">Customizing multiple create</h4>
|
||||
<p>The default implementation for multiple object creation is to simply call <code>.create()</code> for each item in the list. If you want to customize this behavior, you'll need to customize the <code>.create()</code> method on <code>ListSerializer</code> class that is used when <code>many=True</code> is passed.</p>
|
||||
<p>For example:</p>
|
||||
<pre><code>class BookListSerializer(serializers.ListSerializer):
|
||||
def create(self, validated_data):
|
||||
books = [Book(**item) for item in validated_data]
|
||||
return Book.objects.bulk_create(books)
|
||||
|
||||
class BookSerializer(serializers.Serializer):
|
||||
...
|
||||
class Meta:
|
||||
model = Account
|
||||
fields = ('account_url', 'account_name', 'users', 'created')
|
||||
view_name = 'account_detail'
|
||||
lookup_field='account_name'
|
||||
list_serializer_class = BookListSerializer
|
||||
</code></pre>
|
||||
<h4 id="customizing-multiple-update">Customizing multiple update</h4>
|
||||
<p>By default the <code>ListSerializer</code> class does not support multiple updates. This is because the behavior that should be expected for insertions and deletions is ambiguous.</p>
|
||||
<p>To support multiple updates you'll need to do so explicitly. When writing your multiple update code make sure to keep the following in mind:</p>
|
||||
<ul>
|
||||
<li>How do you determine which instance should be updated for each item in the list of data?</li>
|
||||
<li>How should insertions be handled? Are they invalid, or do they create new objects?</li>
|
||||
<li>How should removals be handled? Do they imply object deletion, or removing a relationship? Should they be silently ignored, or are they invalid?</li>
|
||||
<li>How should ordering be handled? Does changing the position of two items imply any state change or is it ignored? </li>
|
||||
</ul>
|
||||
<p>Here's an example of how you might choose to implement multiple updates:</p>
|
||||
<pre><code>class BookListSerializer(serializers.ListSerializer):
|
||||
def update(self, instance, validated_data):
|
||||
# Maps for id->instance and id->data item.
|
||||
book_mapping = {book.id: book for book in instance}
|
||||
data_mapping = {item['id']: item for item in validated_data}
|
||||
|
||||
# Perform creations and updates.
|
||||
ret = []
|
||||
for book_id, data in data_mapping.items():
|
||||
book = book_mapping.get(book_id, None):
|
||||
if book is None:
|
||||
ret.append(self.child.create(data))
|
||||
else:
|
||||
ret.append(self.child.update(book, data))
|
||||
|
||||
# Perform deletions.
|
||||
for book_id, book in book_mapping.items():
|
||||
if book_id not in data_mapping:
|
||||
book.delete()
|
||||
|
||||
return ret
|
||||
|
||||
class BookSerializer(serializers.Serializer):
|
||||
...
|
||||
class Meta:
|
||||
list_serializer_class = BookListSerializer
|
||||
</code></pre>
|
||||
<p>It is possible that a third party package may be included alongside the 3.1 release that provides some automatic support for multiple update operations, similar to the <code>allow_add_remove</code> behavior that was present in REST framework 2.</p>
|
||||
<hr />
|
||||
<h1 id="baseserializer">BaseSerializer</h1>
|
||||
<p><code>BaseSerializer</code> class that can be used to easily support alternative serialization and deserialization styles.</p>
|
||||
<p>This class implements the same basic API as the <code>Serializer</code> class:</p>
|
||||
<ul>
|
||||
<li><code>.data</code> - Returns the outgoing primitive representation.</li>
|
||||
<li><code>.is_valid()</code> - Deserializes and validates incoming data.</li>
|
||||
<li><code>.validated_data</code> - Returns the validated incoming data.</li>
|
||||
<li><code>.errors</code> - Returns an errors during validation.</li>
|
||||
<li><code>.save()</code> - Persists the validated data into an object instance.</li>
|
||||
</ul>
|
||||
<p>There are four methods that can be overridden, depending on what functionality you want the serializer class to support:</p>
|
||||
<ul>
|
||||
<li><code>.to_representation()</code> - Override this to support serialization, for read operations.</li>
|
||||
<li><code>.to_internal_value()</code> - Override this to support deserialization, for write operations.</li>
|
||||
<li><code>.create()</code> and <code>.update()</code> - Overide either or both of these to support saving instances.</li>
|
||||
</ul>
|
||||
<p>Because this class provides the same interface as the <code>Serializer</code> class, you can use it with the existing generic class based views exactly as you would for a regular <code>Serializer</code> or <code>ModelSerializer</code>.</p>
|
||||
<p>The only difference you'll notice when doing so is the <code>BaseSerializer</code> classes will not generate HTML forms in the browsable API. This is because the data they return does not include all the field information that would allow each field to be rendered into a suitable HTML input.</p>
|
||||
<h5 id="read-only-baseserializer-classes">Read-only <code>BaseSerializer</code> classes</h5>
|
||||
<p>To implement a read-only serializer using the <code>BaseSerializer</code> class, we just need to override the <code>.to_representation()</code> method. Let's take a look at an example using a simple Django model:</p>
|
||||
<pre><code>class HighScore(models.Model):
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
player_name = models.CharField(max_length=10)
|
||||
score = models.IntegerField()
|
||||
</code></pre>
|
||||
<p>It's simple to create a read-only serializer for converting <code>HighScore</code> instances into primitive data types.</p>
|
||||
<pre><code>class HighScoreSerializer(serializers.BaseSerializer):
|
||||
def to_representation(self, obj):
|
||||
return {
|
||||
'score': obj.score,
|
||||
'player_name': obj.player_name
|
||||
}
|
||||
</code></pre>
|
||||
<p>We can now use this class to serialize single <code>HighScore</code> instances:</p>
|
||||
<pre><code>@api_view(['GET'])
|
||||
def high_score(request, pk):
|
||||
instance = HighScore.objects.get(pk=pk)
|
||||
serializer = HighScoreSerializer(instance)
|
||||
return Response(serializer.data)
|
||||
</code></pre>
|
||||
<p>Or use it to serialize multiple instances:</p>
|
||||
<pre><code>@api_view(['GET'])
|
||||
def all_high_scores(request):
|
||||
queryset = HighScore.objects.order_by('-score')
|
||||
serializer = HighScoreSerializer(queryset, many=True)
|
||||
return Response(serializer.data)
|
||||
</code></pre>
|
||||
<h5 id="read-write-baseserializer-classes">Read-write <code>BaseSerializer</code> classes</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>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>Here's a complete example of our previous <code>HighScoreSerializer</code>, that's been updated to support both read and write operations.</p>
|
||||
<pre><code>class HighScoreSerializer(serializers.BaseSerializer):
|
||||
def to_internal_value(self, data):
|
||||
score = data.get('score')
|
||||
player_name = data.get('player_name')
|
||||
|
||||
# Perform the data validation.
|
||||
if not score:
|
||||
raise ValidationError({
|
||||
'score': 'This field is required.'
|
||||
})
|
||||
if not player_name:
|
||||
raise ValidationError({
|
||||
'player_name': 'This field is required.'
|
||||
})
|
||||
if len(player_name) > 10:
|
||||
raise ValidationError({
|
||||
'player_name': 'May not be more than 10 characters.'
|
||||
})
|
||||
|
||||
# Return the validated values. This will be available as
|
||||
# the `.validated_data` property.
|
||||
return {
|
||||
'score': int(score),
|
||||
'player_name': player_name
|
||||
}
|
||||
|
||||
def to_representation(self, obj):
|
||||
return {
|
||||
'score': obj.score,
|
||||
'player_name': obj.player_name
|
||||
}
|
||||
|
||||
def create(self, validated_data):
|
||||
return HighScore.objects.create(**validated_data)
|
||||
</code></pre>
|
||||
<h4 id="creating-new-base-classes">Creating new base classes</h4>
|
||||
<p>The <code>BaseSerializer</code> class is also useful if you want to implement new generic serializer classes for dealing with particular serialization styles, or for integrating with alternative storage backends.</p>
|
||||
<p>The following class is an example of a generic serializer that can handle coercing arbitrary objects into primitive representations.</p>
|
||||
<pre><code>class ObjectSerializer(serializers.BaseSerializer):
|
||||
"""
|
||||
A read-only serializer that coerces arbitrary complex objects
|
||||
into primitive representations.
|
||||
"""
|
||||
def to_representation(self, obj):
|
||||
for attribute_name in dir(obj):
|
||||
attribute = getattr(obj, attribute_name)
|
||||
if attribute_name('_'):
|
||||
# Ignore private attributes.
|
||||
pass
|
||||
elif hasattr(attribute, '__call__'):
|
||||
# Ignore methods and other callables.
|
||||
pass
|
||||
elif isinstance(attribute, (str, int, bool, float, type(None))):
|
||||
# Primitive types can be passed through unmodified.
|
||||
output[attribute_name] = attribute
|
||||
elif isinstance(attribute, list):
|
||||
# Recursively deal with items in lists.
|
||||
output[attribute_name] = [
|
||||
self.to_representation(item) for item in attribute
|
||||
]
|
||||
elif isinstance(attribute, dict):
|
||||
# Recursively deal with items in dictionaries.
|
||||
output[attribute_name] = {
|
||||
str(key): self.to_representation(value)
|
||||
for key, value in attribute.items()
|
||||
}
|
||||
else:
|
||||
# Force anything else to its string representation.
|
||||
output[attribute_name] = str(attribute)
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="advanced-serializer-usage">Advanced serializer usage</h1>
|
||||
<p>You can create customized subclasses of <code>ModelSerializer</code> or <code>HyperlinkedModelSerializer</code> that use a different set of default fields.</p>
|
||||
<p>Doing so should be considered advanced usage, and will only be needed if you have some particular serializer requirements that you often need to repeat.</p>
|
||||
<h2 id="overriding-serialization-and-deserialization-behavior">Overriding serialization and deserialization behavior</h2>
|
||||
<p>If you need to alter the serialization, deserialization or validation of a serializer class you can do so by overriding the <code>.to_representation()</code> or <code>.to_internal_value()</code> methods.</p>
|
||||
<p>Some reasons this might be useful include...</p>
|
||||
<ul>
|
||||
<li>Adding new behavior for new serializer base classes.</li>
|
||||
<li>Modifying the behavior slightly for an existing class.</li>
|
||||
<li>Improving serialization performance for a frequently accessed API endpoint that returns lots of data.</li>
|
||||
</ul>
|
||||
<p>The signatures for these methods are as follows:</p>
|
||||
<h4 id="to_representationself-obj"><code>.to_representation(self, obj)</code></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>
|
||||
<h4 id="to_internal_valueself-data"><code>.to_internal_value(self, data)</code></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>. Typically the <code>errors</code> argument here will be a dictionary mapping field names to error messages.</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="dynamically-modifying-fields">Dynamically modifying fields</h2>
|
||||
<p>Once a serializer has been initialized, the dictionary of fields that are set on the serializer may be accessed using the <code>.fields</code> attribute. Accessing and modifying this attribute allows you to dynamically modify the serializer.</p>
|
||||
<p>Modifying the <code>fields</code> argument directly allows you to do interesting things such as changing the arguments on serializer fields at runtime, rather than at the point of declaring the serializer.</p>
|
||||
|
@ -890,7 +1242,7 @@ The <code>ModelSerializer</code> class lets you automatically create a Serialize
|
|||
# Instantiate the superclass normally
|
||||
super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)
|
||||
|
||||
if fields:
|
||||
if fields is not None:
|
||||
# Drop any fields that are not specified in the `fields` argument.
|
||||
allowed = set(fields)
|
||||
existing = set(self.fields.keys())
|
||||
|
@ -909,29 +1261,11 @@ The <code>ModelSerializer</code> class lets you automatically create a Serialize
|
|||
>>> print UserSerializer(user, fields=('id', 'email'))
|
||||
{'id': 2, 'email': 'jon@example.com'}
|
||||
</code></pre>
|
||||
<h2 id="customising-the-default-fields">Customising the default fields</h2>
|
||||
<p>The <code>field_mapping</code> attribute is a dictionary that maps model classes to serializer classes. Overriding the attribute will let you set a different set of default serializer classes.</p>
|
||||
<p>For more advanced customization than simply changing the default serializer class you can override various <code>get_<field_type>_field</code> methods. Doing so will allow you to customize the arguments that each serializer field is initialized with. Each of these methods may either return a field or serializer instance, or <code>None</code>.</p>
|
||||
<h3 id="get_pk_field">get_pk_field</h3>
|
||||
<p><strong>Signature</strong>: <code>.get_pk_field(self, model_field)</code></p>
|
||||
<p>Returns the field instance that should be used to represent the pk field.</p>
|
||||
<h3 id="get_nested_field">get_nested_field</h3>
|
||||
<p><strong>Signature</strong>: <code>.get_nested_field(self, model_field, related_model, to_many)</code></p>
|
||||
<p>Returns the field instance that should be used to represent a related field when <code>depth</code> is specified as being non-zero.</p>
|
||||
<p>Note that the <code>model_field</code> argument will be <code>None</code> for reverse relationships. The <code>related_model</code> argument will be the model class for the target of the field. The <code>to_many</code> argument will be a boolean indicating if this is a to-one or to-many relationship.</p>
|
||||
<h3 id="get_related_field">get_related_field</h3>
|
||||
<p><strong>Signature</strong>: <code>.get_related_field(self, model_field, related_model, to_many)</code></p>
|
||||
<p>Returns the field instance that should be used to represent a related field when <code>depth</code> is not specified, or when nested representations are being used and the depth reaches zero.</p>
|
||||
<p>Note that the <code>model_field</code> argument will be <code>None</code> for reverse relationships. The <code>related_model</code> argument will be the model class for the target of the field. The <code>to_many</code> argument will be a boolean indicating if this is a to-one or to-many relationship.</p>
|
||||
<h3 id="get_field">get_field</h3>
|
||||
<p><strong>Signature</strong>: <code>.get_field(self, model_field)</code></p>
|
||||
<p>Returns the field instance that should be used for non-relational, non-pk fields.</p>
|
||||
<h3 id="example_1">Example</h3>
|
||||
<p>The following custom model serializer could be used as a base class for model serializers that should always exclude the pk by default.</p>
|
||||
<pre><code>class NoPKModelSerializer(serializers.ModelSerializer):
|
||||
def get_pk_field(self, model_field):
|
||||
return None
|
||||
</code></pre>
|
||||
<h2 id="customizing-the-default-fields">Customizing the default fields</h2>
|
||||
<p>REST framework 2 provided an API to allow developers to override how a <code>ModelSerializer</code> class would automatically generate the default set of fields.</p>
|
||||
<p>This API included the <code>.get_field()</code>, <code>.get_pk_field()</code> and other methods.</p>
|
||||
<p>Because the serializers have been fundamentally redesigned with 3.0 this API no longer exists. You can still modify the fields that get created but you'll need to refer to the source code, and be aware that if the changes you make are against private bits of API then they may be subject to change.</p>
|
||||
<p>A new interface for controlling this behavior is currently planned for REST framework 3.1.</p>
|
||||
<hr />
|
||||
<h1 id="third-party-packages">Third party packages</h1>
|
||||
<p>The following third party packages are also available.</p>
|
||||
|
@ -955,7 +1289,7 @@ The <code>ModelSerializer</code> class lets you automatically create a Serialize
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -445,7 +453,7 @@ print api_settings.DEFAULT_AUTHENTICATION_CLASSES
|
|||
)
|
||||
</code></pre>
|
||||
<h4 id="default_parser_classes">DEFAULT_PARSER_CLASSES</h4>
|
||||
<p>A list or tuple of parser classes, that determines the default set of parsers used when accessing the <code>request.DATA</code> property.</p>
|
||||
<p>A list or tuple of parser classes, that determines the default set of parsers used when accessing the <code>request.data</code> property.</p>
|
||||
<p>Default:</p>
|
||||
<pre><code>(
|
||||
'rest_framework.parsers.JSONParser',
|
||||
|
@ -677,7 +685,7 @@ If set to <code>None</code> then generic filtering is disabled.</p>
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -492,7 +500,7 @@ is_server_error() # 5xx
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -654,7 +662,7 @@ self.assertEqual(response.content, '{"username": "lauren", "id": 4}')
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -563,7 +571,7 @@ class UploadView(APIView):
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
642
api-guide/validators/index.html
Normal file
642
api-guide/validators/index.html
Normal file
|
@ -0,0 +1,642 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta charset="utf-8">
|
||||
<title>Validators - Django REST framework</title>
|
||||
<link href="../../img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<link rel="canonical" href="http://www.django-rest-framework.org/api-guide/validators/" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Validators">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="../../css/prettify.css" rel="stylesheet">
|
||||
<link href="../../css/bootstrap.css" rel="stylesheet">
|
||||
<link href="../../css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="../../css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script');
|
||||
ga.type = 'text/javascript';
|
||||
ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
span.fusion-wrap a {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
color: black;
|
||||
}
|
||||
a.fusion-poweredby {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
div.promo {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="prev" href="../authentication">
|
||||
Next <i class="icon-arrow-right icon-white"></i>
|
||||
</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="next" href="../relations">
|
||||
<i class="icon-arrow-left icon-white"></i> Previous
|
||||
</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</a>
|
||||
<a class="brand" href="http://www.django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
|
||||
<!-- Main navigation -->
|
||||
<ul class="nav navbar-nav">
|
||||
<li ><a href="/">Home</a></li>
|
||||
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
|
||||
<li >
|
||||
<a href="../../tutorial/quickstart">Quickstart</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../tutorial/1-serialization">1 - Serialization</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../tutorial/2-requests-and-responses">2 - Requests and responses</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../tutorial/3-class-based-views">3 - Class based views</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../tutorial/4-authentication-and-permissions">4 - Authentication and permissions</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../tutorial/5-relationships-and-hyperlinked-apis">5 - Relationships and hyperlinked APIs</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../tutorial/6-viewsets-and-routers">6 - Viewsets and routers</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="dropdown active">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
|
||||
<li >
|
||||
<a href="../requests">Requests</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../responses">Responses</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../views">Views</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../generic-views">Generic views</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../viewsets">Viewsets</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../routers">Routers</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../parsers">Parsers</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../renderers">Renderers</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../serializers">Serializers</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../fields">Serializer fields</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li class="active" >
|
||||
<a href=".">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../permissions">Permissions</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../throttling">Throttling</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../filtering">Filtering</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../pagination">Pagination</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../content-negotiation">Content negotiation</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../format-suffixes">Format suffixes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../reverse">Returning URLs</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../exceptions">Exceptions</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../status-codes">Status codes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../testing">Testing</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../settings">Settings</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
|
||||
<li >
|
||||
<a href="../../topics/documenting-your-api">Documenting your API</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/browser-enhancements">Browser enhancements</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/browsable-api">The Browsable API</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/rest-hypermedia-hateoas">REST, Hypermedia & HATEOAS</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/third-party-resources">Third Party Resources</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/contributing">Contributing to REST framework</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/2.2-announcement">2.2 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/2.3-announcement">2.3 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/release-notes">Release Notes</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/credits">Credits</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<!--/.nav-collapse -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
|
||||
'//www.google.com/cse/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:search></gcse:search>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span3">
|
||||
<!-- TODO
|
||||
<p style="margin-top: -12px">
|
||||
<a class="btn btn-mini btn-primary" style="width: 60px">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</a>
|
||||
</p>
|
||||
-->
|
||||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="main">
|
||||
<a href="#validators">Validators</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#validation-in-rest-framework">Validation in REST framework</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#uniquevalidator">UniqueValidator</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#uniquetogethervalidator">UniqueTogetherValidator</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#uniquefordatevalidator">UniqueForDateValidator</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#uniqueformonthvalidator">UniqueForMonthValidator</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#uniqueforyearvalidator">UniqueForYearValidator</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="main">
|
||||
<a href="#advanced-default-argument-usage">Advanced 'default' argument usage</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#currentuserdefault">CurrentUserDefault</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#createonlydefault">CreateOnlyDefault</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="main">
|
||||
<a href="#writing-custom-validators">Writing custom validators</a>
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#function-based">Function based</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#class-based">Class based</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
|
||||
|
||||
<p><a class="github" href="validators.py"></a></p>
|
||||
<hr />
|
||||
<p><strong>Note</strong>: This is the documentation for the <strong>version 3.0</strong> of REST framework. Documentation for <a href="http://tomchristie.github.io/rest-framework-2-docs/">version 2.4</a> is also available.</p>
|
||||
<hr />
|
||||
<h1 id="validators">Validators</h1>
|
||||
<blockquote>
|
||||
<p>Validators can be useful for re-using validation logic between different types of fields.</p>
|
||||
<p>— <a href="https://docs.djangoproject.com/en/dev/ref/validators/">Django documentation</a></p>
|
||||
</blockquote>
|
||||
<p>Most of the time you're dealing with validation in REST framework you'll simply be relying on the default field validation, or writing explicit validation methods on serializer or field classes.</p>
|
||||
<p>However, sometimes you'll want to place your validation logic into reusable components, so that it can easily be reused throughout your codebase. This can be achieved by using validator functions and validator classes.</p>
|
||||
<h2 id="validation-in-rest-framework">Validation in REST framework</h2>
|
||||
<p>Validation in Django REST framework serializers is handled a little differently to how validation works in Django's <code>ModelForm</code> class.</p>
|
||||
<p>With <code>ModelForm</code> the validation is performed partially on the form, and partially on the model instance. With REST framework the validation is performed entirely on the serializer class. This is advantageous for the following reasons:</p>
|
||||
<ul>
|
||||
<li>It introduces a proper separation of concerns, making your code behavior more obvious.</li>
|
||||
<li>It is easy to switch between using shortcut <code>ModelSerializer</code> classes and using explicit <code>Serializer</code> classes. Any validation behavior being used for <code>ModelSerializer</code> is simple to replicate.</li>
|
||||
<li>Printing the <code>repr</code> of a serializer instance will show you exactly what validation rules it applies. There's no extra hidden validation behavior being called on the model instance.</li>
|
||||
</ul>
|
||||
<p>When you're using <code>ModelSerializer</code> all of this is handled automatically for you. If you want to drop down to using a <code>Serializer</code> classes instead, then you need to define the validation rules explicitly.</p>
|
||||
<h4 id="example">Example</h4>
|
||||
<p>As an example of how REST framework uses explicit validation, we'll take a simple model class that has a field with a uniqueness constraint.</p>
|
||||
<pre><code>class CustomerReportRecord(models.Model):
|
||||
time_raised = models.DateTimeField(default=timezone.now, editable=False)
|
||||
reference = models.CharField(unique=True, max_length=20)
|
||||
description = models.TextField()
|
||||
</code></pre>
|
||||
<p>Here's a basic <code>ModelSerializer</code> that we can use for creating or updating instances of <code>CustomerReportRecord</code>:</p>
|
||||
<pre><code>class CustomerReportSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = CustomerReportRecord
|
||||
</code></pre>
|
||||
<p>If we open up the Django shell using <code>manage.py shell</code> we can now </p>
|
||||
<pre><code>>>> from project.example.serializers import CustomerReportSerializer
|
||||
>>> serializer = CustomerReportSerializer()
|
||||
>>> print(repr(serializer))
|
||||
CustomerReportSerializer():
|
||||
id = IntegerField(label='ID', read_only=True)
|
||||
time_raised = DateTimeField(read_only=True)
|
||||
reference = CharField(max_length=20, validators=[<UniqueValidator(queryset=CustomerReportRecord.objects.all())>])
|
||||
description = CharField(style={'type': 'textarea'})
|
||||
</code></pre>
|
||||
<p>The interesting bit here is the <code>reference</code> field. We can see that the uniqueness constraint is being explicitly enforced by a validator on the serializer field.</p>
|
||||
<p>Because of this more explicit style REST framework includes a few validator classes that are not available in core Django. These classes are detailed below.</p>
|
||||
<hr />
|
||||
<h2 id="uniquevalidator">UniqueValidator</h2>
|
||||
<p>This validator can be used to enforce the <code>unique=True</code> constraint on model fields.
|
||||
It takes a single required argument, and an optional <code>messages</code> argument:</p>
|
||||
<ul>
|
||||
<li><code>queryset</code> <em>required</em> - This is the queryset against which uniqueness should be enforced.</li>
|
||||
<li><code>message</code> - The error message that should be used when validation fails.</li>
|
||||
</ul>
|
||||
<p>This validator should be applied to <em>serializer fields</em>, like so:</p>
|
||||
<pre><code>slug = SlugField(
|
||||
max_length=100,
|
||||
validators=[UniqueValidator(queryset=BlogPost.objects.all())]
|
||||
)
|
||||
</code></pre>
|
||||
<h2 id="uniquetogethervalidator">UniqueTogetherValidator</h2>
|
||||
<p>This validator can be used to enforce <code>unique_together</code> constraints on model instances.
|
||||
It has two required arguments, and a single optional <code>messages</code> argument:</p>
|
||||
<ul>
|
||||
<li><code>queryset</code> <em>required</em> - This is the queryset against which uniqueness should be enforced.</li>
|
||||
<li><code>fields</code> <em>required</em> - A list or tuple of field names which should make a unique set. These must exist as fields on the serializer class.</li>
|
||||
<li><code>message</code> - The error message that should be used when validation fails.</li>
|
||||
</ul>
|
||||
<p>The validator should be applied to <em>serializer classes</em>, like so:</p>
|
||||
<pre><code>class ExampleSerializer(serializers.Serializer):
|
||||
# ...
|
||||
class Meta:
|
||||
# ToDo items belong to a parent list, and have an ordering defined
|
||||
# by the 'position' field. No two items in a given list may share
|
||||
# the same position.
|
||||
validators = [
|
||||
UniqueTogetherValidator(
|
||||
queryset=ToDoItem.objects.all(),
|
||||
fields=('list', 'position')
|
||||
)
|
||||
]
|
||||
</code></pre>
|
||||
<hr />
|
||||
<p><strong>Note</strong>: The <code>UniqueTogetherValidation</code> class always imposes an implicit constraint that all the fields it applies to are always treated as required. Fields with <code>default</code> values are an exception to this as they always supply a value even when omitted from user input.</p>
|
||||
<hr />
|
||||
<h2 id="uniquefordatevalidator">UniqueForDateValidator</h2>
|
||||
<h2 id="uniqueformonthvalidator">UniqueForMonthValidator</h2>
|
||||
<h2 id="uniqueforyearvalidator">UniqueForYearValidator</h2>
|
||||
<p>These validators can be used to enforce the <code>unique_for_date</code>, <code>unique_for_month</code> and <code>unique_for_year</code> constraints on model instances. They take the following arguments:</p>
|
||||
<ul>
|
||||
<li><code>queryset</code> <em>required</em> - This is the queryset against which uniqueness should be enforced.</li>
|
||||
<li><code>field</code> <em>required</em> - A field name against which uniqueness in the given date range will be validated. This must exist as a field on the serializer class.</li>
|
||||
<li><code>date_field</code> <em>required</em> - A field name which will be used to determine date range for the uniqueness constrain. This must exist as a field on the serializer class.</li>
|
||||
<li><code>message</code> - The error message that should be used when validation fails.</li>
|
||||
</ul>
|
||||
<p>The validator should be applied to <em>serializer classes</em>, like so:</p>
|
||||
<pre><code>class ExampleSerializer(serializers.Serializer):
|
||||
# ...
|
||||
class Meta:
|
||||
# Blog posts should have a slug that is unique for the current year.
|
||||
validators = [
|
||||
UniqueForYearValidator(
|
||||
queryset=BlogPostItem.objects.all(),
|
||||
field='slug',
|
||||
date_field='published'
|
||||
)
|
||||
]
|
||||
</code></pre>
|
||||
<p>The date field that is used for the validation is always required to be present on the serializer class. You can't simply rely on a model class <code>default=...</code>, because the value being used for the default wouldn't be generated until after the validation has run.</p>
|
||||
<p>There are a couple of styles you may want to use for this depending on how you want your API to behave. If you're using <code>ModelSerializer</code> you'll probably simply rely on the defaults that REST framework generates for you, but if you are using <code>Serializer</code> or simply want more explicit control, use on of the styles demonstrated below.</p>
|
||||
<h4 id="using-with-a-writable-date-field">Using with a writable date field.</h4>
|
||||
<p>If you want the date field to be writable the only thing worth noting is that you should ensure that it is always available in the input data, either by setting a <code>default</code> argument, or by setting <code>required=True</code>.</p>
|
||||
<pre><code>published = serializers.DateTimeField(required=True)
|
||||
</code></pre>
|
||||
<h4 id="using-with-a-read-only-date-field">Using with a read-only date field.</h4>
|
||||
<p>If you want the date field to be visible, but not editable by the user, then set <code>read_only=True</code> and additionally set a <code>default=...</code> argument.</p>
|
||||
<pre><code>published = serializers.DateTimeField(read_only=True, default=timezone.now)
|
||||
</code></pre>
|
||||
<p>The field will not be writable to the user, but the default value will still be passed through to the <code>validated_data</code>.</p>
|
||||
<h4 id="using-with-a-hidden-date-field">Using with a hidden date field.</h4>
|
||||
<p>If you want the date field to be entirely hidden from the user, then use <code>HiddenField</code>. This field type does not accept user input, but instead always returns it's default value to the <code>validated_data</code> in the serializer.</p>
|
||||
<pre><code>published = serializers.HiddenField(default=timezone.now)
|
||||
</code></pre>
|
||||
<hr />
|
||||
<p><strong>Note</strong>: The <code>UniqueFor<Range>Validation</code> classes always imposes an implicit constraint that the fields they are applied to are always treated as required. Fields with <code>default</code> values are an exception to this as they always supply a value even when omitted from user input.</p>
|
||||
<hr />
|
||||
<h1 id="advanced-default-argument-usage">Advanced 'default' argument usage</h1>
|
||||
<p>Validators that are applied across multiple fields in the serializer can sometimes require a field input that should not be provided by the API client, but that <em>is</em> available as input to the validator.</p>
|
||||
<p>Two patterns that you may want to use for this sort of validation include:</p>
|
||||
<ul>
|
||||
<li>Using <code>HiddenField</code>. This field will be present in <code>validated_data</code> but <em>will not</em> be used in the serializer output representation.</li>
|
||||
<li>Using a standard field with <code>read_only=True</code>, but that also includes a <code>default=…</code> argument. This field <em>will</em> be used in the serializer output representation, but cannot be set directly by the user.</li>
|
||||
</ul>
|
||||
<p>REST framework includes a couple of defaults that may be useful in this context.</p>
|
||||
<h4 id="currentuserdefault">CurrentUserDefault</h4>
|
||||
<p>A default class that can be used to represent the current user. In order to use this, the 'request' must have been provided as part of the context dictionary when instantiating the serializer.</p>
|
||||
<pre><code>owner = serializers.HiddenField(
|
||||
default=CurrentUserDefault()
|
||||
)
|
||||
</code></pre>
|
||||
<h4 id="createonlydefault">CreateOnlyDefault</h4>
|
||||
<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>
|
||||
<pre><code>created_at = serializers.DateTimeField(
|
||||
read_only=True,
|
||||
default=CreateOnlyDefault(timezone.now)
|
||||
)
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="writing-custom-validators">Writing custom validators</h1>
|
||||
<p>You can use any of Django's existing validators, or write your own custom validators.</p>
|
||||
<h2 id="function-based">Function based</h2>
|
||||
<p>A validator may be any callable that raises a <code>serializers.ValidationError</code> on failure.</p>
|
||||
<pre><code>def even_number(value):
|
||||
if value % 2 != 0:
|
||||
raise serializers.ValidationError('This field must be an even number.')
|
||||
</code></pre>
|
||||
<h2 id="class-based">Class based</h2>
|
||||
<p>To write a class based validator, use the <code>__call__</code> method. Class based validators are useful as they allow you to parameterize and reuse behavior.</p>
|
||||
<pre><code>class MultipleOf:
|
||||
def __init__(self, base):
|
||||
self.base = base
|
||||
|
||||
def __call__(self, value):
|
||||
if value % self.base != 0
|
||||
message = 'This field must be a multiple of %d.' % self.base
|
||||
raise serializers.ValidationError(message)
|
||||
</code></pre>
|
||||
<h4 id="using-set_context">Using <code>set_context()</code></h4>
|
||||
<p>In some advanced cases you might want a validator to be passed the serializer field it is being used with as additional context. You can do so by declaring a <code>set_context</code> method on a class based validator.</p>
|
||||
<pre><code>def set_context(self, serializer_field):
|
||||
# Determine if this is an update or a create operation.
|
||||
# In `__call__` we can then use that information to modify the validation behavior.
|
||||
self.is_update = serializer_field.parent.instance is not None
|
||||
</code></pre>
|
||||
|
||||
</div>
|
||||
<!--/span-->
|
||||
</div>
|
||||
<!--/row-->
|
||||
</div>
|
||||
<!--/.fluid-container-->
|
||||
</div>
|
||||
<!--/.body content-->
|
||||
<div id="push"></div>
|
||||
</div>
|
||||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="../../js/jquery-1.8.1-min.js"></script>
|
||||
<script src="../../js/prettify-1.0.js"></script>
|
||||
<script src="../../js/bootstrap-2.1.1-min.js"></script>
|
||||
|
||||
<script>
|
||||
//$('.side-nav').scrollspy()
|
||||
var shiftWindow = function() {
|
||||
scrollBy(0, -50)
|
||||
};
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav to no higher than browser window
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function() {
|
||||
$(window).resize(function() {
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -478,15 +486,22 @@ This method is used to enforce permissions and throttling, and perform content n
|
|||
</blockquote>
|
||||
<p>REST framework also allows you to work with regular function based views. It provides a set of simple decorators that wrap your function based views to ensure they receive an instance of <code>Request</code> (rather than the usual Django <code>HttpRequest</code>) and allows them to return a <code>Response</code> (instead of a Django <code>HttpResponse</code>), and allow you to configure how the request is processed.</p>
|
||||
<h2 id="api_view">@api_view()</h2>
|
||||
<p><strong>Signature:</strong> <code>@api_view(http_method_names)</code></p>
|
||||
<p>The core of this functionality is the <code>api_view</code> decorator, which takes a list of HTTP methods that your view should respond to. For example, this is how you would write a very simple view that just manually returns some data:</p>
|
||||
<p><strong>Signature:</strong> <code>@api_view(http_method_names=['GET'])</code></p>
|
||||
<p>The core of this functionality is the <code>api_view</code> decorator, which takes a list of HTTP methods that your view should respond to. For example, this is how you would write a very simple view that just manually returns some data:</p>
|
||||
<pre><code>from rest_framework.decorators import api_view
|
||||
|
||||
@api_view(['GET'])
|
||||
@api_view()
|
||||
def hello_world(request):
|
||||
return Response({"message": "Hello, world!"})
|
||||
</code></pre>
|
||||
<p>This view will use the default renderers, parsers, authentication classes etc specified in the <a href="../settings">settings</a>.</p>
|
||||
<p>By default only <code>GET</code> methods will be accepted. Other methods will respond with "405 Method Not Allowed". To alter this behavior, specify which methods the view allows, like so:</p>
|
||||
<pre><code>@api_view(['GET', 'POST'])
|
||||
def hello_world(request):
|
||||
if request.method == 'POST':
|
||||
return Response({"message": "Got some data!", "data": request.data})
|
||||
return Response({"message": "Hello, world!"})
|
||||
</code></pre>
|
||||
<h2 id="api-policy-decorators">API policy decorators</h2>
|
||||
<p>To override the default settings, REST framework provides a set of additional decorators which can be added to your views. These must come <em>after</em> (below) the <code>@api_view</code> decorator. For example, to create a view that uses a <a href="../throttling">throttle</a> to ensure it can only be called once per day by a particular user, use the <code>@throttle_classes</code> decorator, passing a list of throttle classes:</p>
|
||||
<pre><code>from rest_framework.decorators import api_view, throttle_classes
|
||||
|
@ -524,7 +539,7 @@ def view(request):
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -511,7 +519,7 @@ class UserViewSet(viewsets.ModelViewSet):
|
|||
@detail_route(methods=['post'])
|
||||
def set_password(self, request, pk=None):
|
||||
user = self.get_object()
|
||||
serializer = PasswordSerializer(data=request.DATA)
|
||||
serializer = PasswordSerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
user.set_password(serializer.data['password'])
|
||||
user.save()
|
||||
|
@ -615,7 +623,7 @@ class UserViewSet(viewsets.ModelViewSet):
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
18
index.html
18
index.html
|
@ -164,6 +164,10 @@
|
|||
<a href="api-guide/relations/">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="api-guide/validators/">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="api-guide/authentication/">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="topics/2.4-announcement/">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="topics/3.0-announcement/">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="topics/kickstarter-announcement/">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -453,7 +461,8 @@
|
|||
</p>
|
||||
|
||||
<hr />
|
||||
<p><strong>Note</strong>: The incoming 3.0 version has now been merged to the <code>master</code> branch on GitHub. For the source of the currently available PyPI version, please see the <code>2.4.4</code> tag.</p>
|
||||
<p><strong>Note</strong>: This is the documentation for the <strong>version 3.0</strong> of REST framework. Documentation for <a href="http://tomchristie.github.io/rest-framework-2-docs/">version 2.4</a> is also available.</p>
|
||||
<p>For more details see the <a href="topics/3.0-announcement/">3.0 release notes</a>.</p>
|
||||
<hr />
|
||||
<p>
|
||||
<h1 style="position: absolute;
|
||||
|
@ -588,8 +597,8 @@ urlpatterns = [
|
|||
<li><a href="api-guide/renderers/">Renderers</a></li>
|
||||
<li><a href="api-guide/serializers/">Serializers</a></li>
|
||||
<li><a href="api-guide/fields/">Serializer fields</a></li>
|
||||
<li><a href="api-guide/relations/">Serializer relations</a>
|
||||
<!--* [Validators][validators]--></li>
|
||||
<li><a href="api-guide/relations/">Serializer relations</a></li>
|
||||
<li><a href="api-guide/validators/">Validators</a></li>
|
||||
<li><a href="api-guide/authentication/">Authentication</a></li>
|
||||
<li><a href="api-guide/permissions/">Permissions</a></li>
|
||||
<li><a href="api-guide/throttling/">Throttling</a></li>
|
||||
|
@ -617,6 +626,7 @@ urlpatterns = [
|
|||
<li><a href="topics/2.2-announcement/">2.2 Announcement</a></li>
|
||||
<li><a href="topics/2.3-announcement/">2.3 Announcement</a></li>
|
||||
<li><a href="topics/2.4-announcement/">2.4 Announcement</a></li>
|
||||
<li><a href="topics/3.0-announcement/">3.0 Announcement</a></li>
|
||||
<li><a href="topics/kickstarter-announcement/">Kickstarter Announcement</a></li>
|
||||
<li><a href="topics/release-notes/">Release Notes</a></li>
|
||||
<li><a href="topics/credits/">Credits</a></li>
|
||||
|
@ -668,7 +678,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</p>
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -492,7 +500,7 @@ serializer.data
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -629,7 +637,7 @@ urlpatterns = [
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="prev" href="../kickstarter-announcement">
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="prev" href="../3.0-announcement">
|
||||
Next <i class="icon-arrow-right icon-white"></i>
|
||||
</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="next" href="../2.3-announcement">
|
||||
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href=".">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -515,7 +523,7 @@ The lowest supported version of Django is now 1.4.2.</p>
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
1186
topics/3.0-announcement/index.html
Normal file
1186
topics/3.0-announcement/index.html
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -402,7 +410,7 @@
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -460,28 +468,18 @@
|
|||
<p>You can override the <code>BrowsableAPIRenderer.get_context()</code> method to customise the context that gets passed to the template.</p>
|
||||
<h4 id="not-using-basehtml">Not using base.html</h4>
|
||||
<p>For more advanced customization, such as not having a Bootstrap basis or tighter integration with the rest of your site, you can simply choose not to have <code>api.html</code> extend <code>base.html</code>. Then the page content and capabilities are entirely up to you.</p>
|
||||
<h4 id="autocompletion">Autocompletion</h4>
|
||||
<p>When a <code>ChoiceField</code> has too many items, rendering the widget containing all the options can become very slow, and cause the browsable API rendering to perform poorly. One solution is to replace the selector by an autocomplete widget, that only loads and renders a subset of the available options as needed.</p>
|
||||
<p>There are <a href="https://www.djangopackages.com/grids/g/auto-complete/">a variety of packages for autocomplete widgets</a>, such as <a href="https://github.com/yourlabs/django-autocomplete-light">django-autocomplete-light</a>. To setup <code>django-autocomplete-light</code>, follow the <a href="http://django-autocomplete-light.readthedocs.org/en/latest/#install">installation documentation</a>, add the the following to the <code>api.html</code> template:</p>
|
||||
<pre><code>{% block script %}
|
||||
{{ block.super }}
|
||||
{% include 'autocomplete_light/static.html' %}
|
||||
{% endblock %}
|
||||
<h4 id="handling-choicefield-with-large-numbers-of-items">Handling <code>ChoiceField</code> with large numbers of items.</h4>
|
||||
<p>When a relationship or <code>ChoiceField</code> has too many items, rendering the widget containing all the options can become very slow, and cause the browsable API rendering to perform poorly.</p>
|
||||
<p>The simplest option in this case is to replace the select input with a standard text input. For example:</p>
|
||||
<pre><code> author = serializers.HyperlinkedRelatedField(
|
||||
queryset=User.objects.all(),
|
||||
style={'base_template': 'input.html'}
|
||||
)
|
||||
</code></pre>
|
||||
<p>You can now add the <code>autocomplete_light.ChoiceWidget</code> widget to the serializer field.</p>
|
||||
<pre><code>import autocomplete_light
|
||||
|
||||
class BookSerializer(serializers.ModelSerializer):
|
||||
author = serializers.ChoiceField(
|
||||
widget=autocomplete_light.ChoiceWidget('AuthorAutocomplete')
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Book
|
||||
</code></pre>
|
||||
<hr />
|
||||
<p><img alt="Autocomplete" src="../../../img/autocomplete.png" /></p>
|
||||
<p><em>Screenshot of the autocomplete-light widget</em></p>
|
||||
<h4 id="autocomplete">Autocomplete</h4>
|
||||
<p>An alternative, but more complex option would be to replace the input with an autocomplete widget, that only loads and renders a subset of the available options as needed. If you need to do this you'll need to do some work to build a custom autocomplete HTML template yourself.</p>
|
||||
<p>There are <a href="https://www.djangopackages.com/grids/g/auto-complete/">a variety of packages for autocomplete widgets</a>, such as <a href="https://github.com/yourlabs/django-autocomplete-light">django-autocomplete-light</a>, that you may want to refer to. Note that you will not be able to simply include these components as standard widgets, but will need to write the HTML template explicitly. This is because REST framework 3.0 no longer supports the <code>widget</code> keyword argument since it now uses templated HTML generation.</p>
|
||||
<p>Better support for autocomplete inputs is planned in future versions.</p>
|
||||
<hr />
|
||||
|
||||
</div>
|
||||
|
@ -497,7 +495,7 @@ class BookSerializer(serializers.ModelSerializer):
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -445,7 +453,7 @@ as well as how to support content types other than form-encoded data.</p>
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -518,7 +526,6 @@ pip install -r requirements-test.txt
|
|||
<p>Some other tips:</p>
|
||||
<ul>
|
||||
<li>Keep paragraphs reasonably short.</li>
|
||||
<li>Use double spacing after the end of sentences.</li>
|
||||
<li>Don't use abbreviations such as 'e.g.' but instead use the long form, such as 'For example'.</li>
|
||||
</ul>
|
||||
<h2 id="markdown-style">Markdown style</h2>
|
||||
|
@ -566,7 +573,7 @@ More text...
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -572,7 +580,7 @@
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -441,7 +449,7 @@
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
<a class="repo-link btn btn-inverse btn-small " rel="prev" href="../release-notes">
|
||||
Next <i class="icon-arrow-right icon-white"></i>
|
||||
</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="next" href="../2.4-announcement">
|
||||
<a class="repo-link btn btn-inverse btn-small " rel="next" href="../3.0-announcement">
|
||||
<i class="icon-arrow-left icon-white"></i> Previous
|
||||
</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li class="active" >
|
||||
<a href=".">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -509,7 +517,7 @@
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -373,22 +381,6 @@
|
|||
<a href="#20x-series">2.0.x series</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#04x-series">0.4.x series</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#03x-series">0.3.x series</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#02x-series">0.2.x series</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#01x-series">0.1.x series</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -790,7 +782,7 @@
|
|||
<li>Bugfix: Validation errors instead of exceptions when related fields receive incorrect types.</li>
|
||||
<li>Bugfix: Handle ObjectDoesNotExist exception when serializing null reverse one-to-one</li>
|
||||
</ul>
|
||||
<p><strong>Note</strong>: Prior to 2.1.16, The Decimals would render in JSON using floating point if <code>simplejson</code> was installed, but otherwise render using string notation. Now that use of <code>simplejson</code> has been deprecated, Decimals will consistently render using string notation. See <a href="https://github.com/tomchristie/django-rest-framework/issues/582">#582</a> for more details.</p>
|
||||
<p><strong>Note</strong>: Prior to 2.1.16, The Decimals would render in JSON using floating point if <code>simplejson</code> was installed, but otherwise render using string notation. Now that use of <code>simplejson</code> has been deprecated, Decimals will consistently render using string notation. See <a href="../../ticket-582">ticket 582</a> for more details.</p>
|
||||
<h3 id="2115">2.1.15</h3>
|
||||
<p><strong>Date</strong>: 3rd Jan 2013</p>
|
||||
<ul>
|
||||
|
@ -936,124 +928,7 @@
|
|||
<li><strong>Fix all of the things.</strong> (Well, almost.)</li>
|
||||
<li>For more information please see the <a href="../rest-framework-2-announcement">2.0 announcement</a>.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="04x-series">0.4.x series</h2>
|
||||
<h3 id="040">0.4.0</h3>
|
||||
<ul>
|
||||
<li>Supports Django 1.5.</li>
|
||||
<li>Fixes issues with 'HEAD' method.</li>
|
||||
<li>Allow views to specify template used by TemplateRenderer</li>
|
||||
<li>More consistent error responses</li>
|
||||
<li>Some serializer fixes</li>
|
||||
<li>Fix internet explorer ajax behavior</li>
|
||||
<li>Minor xml and yaml fixes</li>
|
||||
<li>Improve setup (e.g. use staticfiles, not the defunct ADMIN_MEDIA_PREFIX)</li>
|
||||
<li>Sensible absolute URL generation, not using hacky set_script_prefix</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="03x-series">0.3.x series</h2>
|
||||
<h3 id="033">0.3.3</h3>
|
||||
<ul>
|
||||
<li>Added DjangoModelPermissions class to support <code>django.contrib.auth</code> style permissions.</li>
|
||||
<li>Use <code>staticfiles</code> for css files.</li>
|
||||
<li>Easier to override. Won't conflict with customized admin styles (e.g. grappelli)</li>
|
||||
<li>Templates are now nicely namespaced.</li>
|
||||
<li>Allows easier overriding.</li>
|
||||
<li>Drop implied 'pk' filter if last arg in urlconf is unnamed.</li>
|
||||
<li>Too magical. Explicit is better than implicit.</li>
|
||||
<li>Saner template variable auto-escaping.</li>
|
||||
<li>Tidier setup.py</li>
|
||||
<li>Updated for URLObject 2.0</li>
|
||||
<li>Bugfixes:</li>
|
||||
<li>Bug with PerUserThrottling when user contains unicode chars.</li>
|
||||
</ul>
|
||||
<h3 id="032">0.3.2</h3>
|
||||
<ul>
|
||||
<li>Bugfixes:</li>
|
||||
<li>Fix 403 for POST and PUT from the UI with UserLoggedInAuthentication (#115)</li>
|
||||
<li>serialize_model method in serializer.py may cause wrong value (#73)</li>
|
||||
<li>Fix Error when clicking OPTIONS button (#146)</li>
|
||||
<li>And many other fixes</li>
|
||||
<li>Remove short status codes</li>
|
||||
<li>Zen of Python: "There should be one-- and preferably only one --obvious way to do it."</li>
|
||||
<li>get_name, get_description become methods on the view - makes them overridable.</li>
|
||||
<li>Improved model mixin API - Hooks for build_query, get_instance_data, get_model, get_queryset, get_ordering</li>
|
||||
</ul>
|
||||
<h3 id="031">0.3.1</h3>
|
||||
<ul>
|
||||
<li>[not documented]</li>
|
||||
</ul>
|
||||
<h3 id="030">0.3.0</h3>
|
||||
<ul>
|
||||
<li>JSONP Support</li>
|
||||
<li>Bugfixes, including support for latest markdown release</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="02x-series">0.2.x series</h2>
|
||||
<h3 id="024">0.2.4</h3>
|
||||
<ul>
|
||||
<li>Fix broken IsAdminUser permission.</li>
|
||||
<li>OPTIONS support.</li>
|
||||
<li>XMLParser.</li>
|
||||
<li>Drop mentions of Blog, BitBucket.</li>
|
||||
</ul>
|
||||
<h3 id="023">0.2.3</h3>
|
||||
<ul>
|
||||
<li>Fix some throttling bugs.</li>
|
||||
<li><code>X-Throttle</code> header on throttling.</li>
|
||||
<li>Support for nesting resources on related models.</li>
|
||||
</ul>
|
||||
<h3 id="022">0.2.2</h3>
|
||||
<ul>
|
||||
<li>Throttling support complete.</li>
|
||||
</ul>
|
||||
<h3 id="021">0.2.1</h3>
|
||||
<ul>
|
||||
<li>Couple of simple bugfixes over 0.2.0</li>
|
||||
</ul>
|
||||
<h3 id="020">0.2.0</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<p>Big refactoring changes since 0.1.0, ask on the discussion group if anything isn't clear.
|
||||
The public API has been massively cleaned up. Expect it to be fairly stable from here on in.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>Resource</code> becomes decoupled into <code>View</code> and <code>Resource</code>, your views should now inherit from <code>View</code>, not <code>Resource</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>The handler functions on views <code>.get() .put() .post()</code> etc, no longer have the <code>content</code> and <code>auth</code> args.
|
||||
Use <code>self.CONTENT</code> inside a view to access the deserialized, validated content.
|
||||
Use <code>self.user</code> inside a view to access the authenticated user.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>allowed_methods</code> and <code>anon_allowed_methods</code> are now defunct. if a method is defined, it's available.
|
||||
The <code>permissions</code> attribute on a <code>View</code> is now used to provide generic permissions checking.
|
||||
Use permission classes such as <code>FullAnonAccess</code>, <code>IsAuthenticated</code> or <code>IsUserOrIsAnonReadOnly</code> to set the permissions.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>The <code>authenticators</code> class becomes <code>authentication</code>. Class names change to <code>Authentication</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>The <code>emitters</code> class becomes <code>renderers</code>. Class names change to <code>Renderers</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>ResponseException</code> becomes <code>ErrorResponse</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>The mixin classes have been nicely refactored, the basic mixins are now <code>RequestMixin</code>, <code>ResponseMixin</code>, <code>AuthMixin</code>, and <code>ResourceMixin</code>
|
||||
You can reuse these mixin classes individually without using the <code>View</code> class.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="01x-series">0.1.x series</h2>
|
||||
<h3 id="011">0.1.1</h3>
|
||||
<ul>
|
||||
<li>Final build before pulling in all the refactoring changes for 0.2, in case anyone needs to hang on to 0.1.</li>
|
||||
</ul>
|
||||
<h3 id="010">0.1.0</h3>
|
||||
<ul>
|
||||
<li>Initial release.</li>
|
||||
</ul>
|
||||
<p>For older release notes, <a href="../../old-release-notes">please see the GitHub repo</a>.</p>
|
||||
|
||||
</div>
|
||||
<!--/span-->
|
||||
|
@ -1068,7 +943,7 @@
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -452,7 +460,7 @@
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -368,11 +376,11 @@
|
|||
|
||||
<h1 id="rest-hypermedia-hateoas">REST, Hypermedia & HATEOAS</h1>
|
||||
<blockquote>
|
||||
<p>You keep using that word "REST". I do not think it means what you think it means.</p>
|
||||
<p>You keep using that word "REST". I do not think it means what you think it means.</p>
|
||||
<p>— Mike Amundsen, <a href="http://vimeo.com/channels/restfest/page:2">REST fest 2012 keynote</a>.</p>
|
||||
</blockquote>
|
||||
<p>First off, the disclaimer. The name "Django REST framework" was chosen simply to sure the project would be easily found by developers. Throughout the documentation we try to use the more simple and technically correct terminology of "Web APIs".</p>
|
||||
<p>If you are serious about designing a Hypermedia APIs, you should look to resources outside of this documentation to help inform your design choices.</p>
|
||||
<p>First off, the disclaimer. The name "Django REST framework" was decided back in early 2011 and was chosen simply to sure the project would be easily found by developers. Throughout the documentation we try to use the more simple and technically correct terminology of "Web APIs".</p>
|
||||
<p>If you are serious about designing a Hypermedia API, you should look to resources outside of this documentation to help inform your design choices.</p>
|
||||
<p>The following fall into the "required reading" category.</p>
|
||||
<ul>
|
||||
<li>Roy Fielding's dissertation - <a href="http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm">Architectural Styles and
|
||||
|
@ -390,7 +398,7 @@ the Design of Network-based Software Architectures</a>.</li>
|
|||
<p>It is self evident that REST framework makes it possible to build Hypermedia APIs. The browsable API that it offers is built on HTML - the hypermedia language of the web.</p>
|
||||
<p>REST framework also includes <a href="../../api-guide/serializers">serialization</a> and <a href="../../api-guide/parsers">parser</a>/<a href="../../api-guide/renderers">renderer</a> components that make it easy to build appropriate media types, <a href="../../api-guide/fields">hyperlinked relations</a> for building well-connected systems, and great support for <a href="../../api-guide/content-negotiation">content negotiation</a>.</p>
|
||||
<h2 id="what-rest-framework-doesnt-provide">What REST framework doesn't provide.</h2>
|
||||
<p>What REST framework doesn't do is give you is machine readable hypermedia formats such as <a href="http://stateless.co/hal_specification.html">HAL</a>, <a href="http://www.amundsen.com/media-types/collection/">Collection+JSON</a>, <a href="http://jsonapi.org/">JSON API</a> or HTML <a href="http://microformats.org/wiki/Main_Page">microformats</a> by default, or the ability to auto-magically create fully HATEOAS style APIs that include hypermedia-based form descriptions and semantically labelled hyperlinks. Doing so would involve making opinionated choices about API design that should really remain outside of the framework's scope.</p>
|
||||
<p>What REST framework doesn't do is give you is machine readable hypermedia formats such as <a href="http://stateless.co/hal_specification.html">HAL</a>, <a href="http://www.amundsen.com/media-types/collection/">Collection+JSON</a>, <a href="http://jsonapi.org/">JSON API</a> or HTML <a href="http://microformats.org/wiki/Main_Page">microformats</a> by default, or the ability to auto-magically create fully HATEOAS style APIs that include hypermedia-based form descriptions and semantically labelled hyperlinks. Doing so would involve making opinionated choices about API design that should really remain outside of the framework's scope.</p>
|
||||
|
||||
</div>
|
||||
<!--/span-->
|
||||
|
@ -405,7 +413,7 @@ the Design of Network-based Software Architectures</a>.</li>
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -373,9 +381,9 @@
|
|||
<h1 id="third-party-resources">Third Party Resources</h1>
|
||||
<h2 id="about-third-party-packages">About Third Party Packages</h2>
|
||||
<p>Third Party Packages allow developers to share code that extends the functionality of Django REST framework, in order to support additional use-cases.</p>
|
||||
<p>We <strong>support</strong>, <strong>encourage</strong> and <strong>strongly favour</strong> the creation of Third Party Packages to encapsulate new behaviour rather than adding additional functionality directly to Django REST Framework.</p>
|
||||
<p>We aim to make creating Third Party Packages as easy as possible, whilst keeping the <strong>simplicity</strong> of the core API and ensuring that <strong>maintenance</strong> of the main project remains under control. If a Third Party Package proves popular it is relatively easy to move it into the main project; removing features is much more problematic.</p>
|
||||
<p>If you have an idea for a new feature please consider how it may be packaged as a Third Party Package. We're always happy to dicuss ideas on the <a href="https://groups.google.com/forum/#!forum/django-rest-framework">Mailing List</a>.</p>
|
||||
<p>We <strong>support</strong>, <strong>encourage</strong> and <strong>strongly favor</strong> the creation of Third Party Packages to encapsulate new behavior rather than adding additional functionality directly to Django REST Framework.</p>
|
||||
<p>We aim to make creating third party packages as easy as possible, whilst keeping a <strong>simple</strong> and <strong>well maintained</strong> core API. By promoting third party packages we ensure that the responsibility for a package remains with its author. If a package proves suitably popular it can always be considered for inclusion into the core REST framework.</p>
|
||||
<p>If you have an idea for a new feature please consider how it may be packaged as a Third Party Package. We're always happy to discuss ideas on the <a href="https://groups.google.com/forum/#!forum/django-rest-framework">Mailing List</a>.</p>
|
||||
<h2 id="how-to-create-a-third-party-package">How to create a Third Party Package</h2>
|
||||
<h3 id="creating-your-package">Creating your package</h3>
|
||||
<p>You can use <a href="https://github.com/jpadilla/cookiecutter-django-rest-framework">this cookiecutter template</a> for creating reusable Django REST Framework packages quickly. Cookiecutter creates projects from project templates. While optional, this cookiecutter template includes best practices from Django REST framework and other packages, as well as a Travis CI configuration, Tox configuration, and a sane setup.py for easy PyPI registration/distribution.</p>
|
||||
|
@ -581,7 +589,7 @@ You probably want to also tag the version now:
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -703,7 +711,7 @@ Quit the server with CONTROL-C.
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -390,9 +398,9 @@
|
|||
<p>From this point we're going to really start covering the core of REST framework.
|
||||
Let's introduce a couple of essential building blocks.</p>
|
||||
<h2 id="request-objects">Request objects</h2>
|
||||
<p>REST framework introduces a <code>Request</code> object that extends the regular <code>HttpRequest</code>, and provides more flexible request parsing. The core functionality of the <code>Request</code> object is the <code>request.DATA</code> attribute, which is similar to <code>request.POST</code>, but more useful for working with Web APIs.</p>
|
||||
<p>REST framework introduces a <code>Request</code> object that extends the regular <code>HttpRequest</code>, and provides more flexible request parsing. The core functionality of the <code>Request</code> object is the <code>request.data</code> attribute, which is similar to <code>request.POST</code>, but more useful for working with Web APIs.</p>
|
||||
<pre><code>request.POST # Only handles form data. Only works for 'POST' method.
|
||||
request.DATA # Handles arbitrary data. Works for 'POST', 'PUT' and 'PATCH' methods.
|
||||
request.data # Handles arbitrary data. Works for 'POST', 'PUT' and 'PATCH' methods.
|
||||
</code></pre>
|
||||
<h2 id="response-objects">Response objects</h2>
|
||||
<p>REST framework also introduces a <code>Response</code> object, which is a type of <code>TemplateResponse</code> that takes unrendered content and uses content negotiation to determine the correct content type to return to the client.</p>
|
||||
|
@ -407,7 +415,7 @@ request.DATA # Handles arbitrary data. Works for 'POST', 'PUT' and 'PATCH' met
|
|||
<li>The <code>APIView</code> class for working with class based views.</li>
|
||||
</ol>
|
||||
<p>These wrappers provide a few bits of functionality such as making sure you receive <code>Request</code> instances in your view, and adding context to <code>Response</code> objects so that content negotiation can be performed.</p>
|
||||
<p>The wrappers also provide behaviour such as returning <code>405 Method Not Allowed</code> responses when appropriate, and handling any <code>ParseError</code> exception that occurs when accessing <code>request.DATA</code> with malformed input.</p>
|
||||
<p>The wrappers also provide behaviour such as returning <code>405 Method Not Allowed</code> responses when appropriate, and handling any <code>ParseError</code> exception that occurs when accessing <code>request.data</code> with malformed input.</p>
|
||||
<h2 id="pulling-it-all-together">Pulling it all together</h2>
|
||||
<p>Okay, let's go ahead and start using these new components to write a few views.</p>
|
||||
<p>We don't need our <code>JSONResponse</code> class in <code>views.py</code> anymore, so go ahead and delete that. Once that's done we can start refactoring our views slightly.</p>
|
||||
|
@ -429,7 +437,7 @@ def snippet_list(request):
|
|||
return Response(serializer.data)
|
||||
|
||||
elif request.method == 'POST':
|
||||
serializer = SnippetSerializer(data=request.DATA)
|
||||
serializer = SnippetSerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
|
@ -452,7 +460,7 @@ def snippet_detail(request, pk):
|
|||
return Response(serializer.data)
|
||||
|
||||
elif request.method == 'PUT':
|
||||
serializer = SnippetSerializer(snippet, data=request.DATA)
|
||||
serializer = SnippetSerializer(snippet, data=request.data)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return Response(serializer.data)
|
||||
|
@ -463,7 +471,7 @@ def snippet_detail(request, pk):
|
|||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
</code></pre>
|
||||
<p>This should all feel very familiar - it is not a lot different from working with regular Django views.</p>
|
||||
<p>Notice that we're no longer explicitly tying our requests or responses to a given content type. <code>request.DATA</code> can handle incoming <code>json</code> requests, but it can also handle <code>yaml</code> and other formats. Similarly we're returning response objects with data, but allowing REST framework to render the response into the correct content type for us.</p>
|
||||
<p>Notice that we're no longer explicitly tying our requests or responses to a given content type. <code>request.data</code> can handle incoming <code>json</code> requests, but it can also handle <code>yaml</code> and other formats. Similarly we're returning response objects with data, but allowing REST framework to render the response into the correct content type for us.</p>
|
||||
<h2 id="adding-optional-format-suffixes-to-our-urls">Adding optional format suffixes to our URLs</h2>
|
||||
<p>To take advantage of the fact that our responses are no longer hardwired to a single content type let's add support for format suffixes to our API endpoints. Using format suffixes gives us URLs that explicitly refer to a given format, and means our API will be able to handle URLs such as <a href="http://example.com/api/items/4.json">http://example.com/api/items/4.json</a>.</p>
|
||||
<p>Start by adding a <code>format</code> keyword argument to both of the views, like so.</p>
|
||||
|
@ -532,7 +540,7 @@ curl -X POST http://127.0.0.1:8000/snippets/ -d '{"code": "print 456"}' -H "Cont
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -388,7 +396,7 @@ class SnippetList(APIView):
|
|||
return Response(serializer.data)
|
||||
|
||||
def post(self, request, format=None):
|
||||
serializer = SnippetSerializer(data=request.DATA)
|
||||
serializer = SnippetSerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
|
@ -412,7 +420,7 @@ class SnippetList(APIView):
|
|||
|
||||
def put(self, request, pk, format=None):
|
||||
snippet = self.get_object(pk)
|
||||
serializer = SnippetSerializer(snippet, data=request.DATA)
|
||||
serializer = SnippetSerializer(snippet, data=request.data)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return Response(serializer.data)
|
||||
|
@ -509,7 +517,7 @@ class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -566,7 +574,7 @@ class IsOwnerOrReadOnly(permissions.BasePermission):
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -519,7 +527,7 @@ urlpatterns += [
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -509,7 +517,7 @@ urlpatterns = [
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@
|
|||
<a href="../../api-guide/relations">Serializer relations</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/validators">Validators</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../api-guide/authentication">Authentication</a>
|
||||
</li>
|
||||
|
@ -263,6 +267,10 @@
|
|||
<a href="../../topics/2.4-announcement">2.4 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/3.0-announcement">3.0 Announcement</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
|
||||
</li>
|
||||
|
@ -530,7 +538,7 @@ REST_FRAMEWORK = {
|
|||
<!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a>
|
||||
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user