mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-12-04 23:44:07 +03:00
Docs tweaks
This commit is contained in:
parent
8f0ce5e546
commit
63f9fe8062
|
@ -126,6 +126,8 @@
|
|||
<li><a href="#integerfield">IntegerField</a></li>
|
||||
<li><a href="#floatfield">FloatField</a></li>
|
||||
<li class="main"><a href="#relational-fields">Relational Fields</a></li>
|
||||
<li><a href="#relatedfield">RelatedField</a></li>
|
||||
<li><a href="#manyrelatedfield">ManyRelatedField</a></li>
|
||||
<li><a href="#primarykeyrelatedfield">PrimaryKeyRelatedField</a></li>
|
||||
<li><a href="#manyprimarykeyrelatedfield">ManyPrimaryKeyRelatedField</a></li>
|
||||
<li><a href="#hyperlinkedrelatedfield">HyperlinkedRelatedField</a></li>
|
||||
|
@ -148,10 +150,39 @@
|
|||
<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>
|
||||
<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, read-only field. You can use this field for any attribute that does not need to support write operations.</p>
|
||||
<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 class="prettyprint lang-py"><code>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):
|
||||
now = datetime.datetime.now()
|
||||
return now > self.payment_expiry
|
||||
</code></pre>
|
||||
<p>A serializer definition that looked like this:</p>
|
||||
<pre class="prettyprint lang-py"><code>class AccountSerializer(serializers.HyperlinkedModelSerializer):
|
||||
expired = Field(source='has_expired')
|
||||
|
||||
class Meta:
|
||||
fields = ('url', 'owner', 'name', 'expired')
|
||||
</code></pre>
|
||||
<p>Would produced output similar to:</p>
|
||||
<pre class="prettyprint lang-py"><code>{
|
||||
'url': 'http://example.com/api/accounts/3/',
|
||||
'owner': 'http://example.com/api/users/12/',
|
||||
'name': 'FooCorp business account',
|
||||
'expired': True
|
||||
}
|
||||
</code></pre>
|
||||
<p>Be default, the <code>Field</code> class will perform a basic translation of the source value into primative datatypes, falling back to unicode representations of complex datatypes when neccesary.</p>
|
||||
<p>You can customize this behaviour by overriding the <code>.to_native(self, value)</code> method.</p>
|
||||
<h2 id="writablefield">WritableField</h2>
|
||||
<p>A field that supports both read and </p>
|
||||
<p>A field that supports both read and write operations. By itself <code>WriteableField</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 it's 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><strong>Signature:</strong> <code>ModelField(model_field=<Django ModelField class>)</code></p>
|
||||
|
@ -168,8 +199,69 @@
|
|||
<hr />
|
||||
<h1 id="relational-fields">Relational Fields</h1>
|
||||
<p>Relational fields are used to represent model relationships. They can be applied to <code>ForeignKey</code>, <code>ManyToManyField</code> and <code>OneToOneField</code> relationships, as well as to reverse relationships, and custom relationships such as <code>GenericForeignKey</code>.</p>
|
||||
<h2 id="relatedfield">RelatedField</h2>
|
||||
<p>This field can be applied to any of the following:</p>
|
||||
<ul>
|
||||
<li>A <code>ForeignKey</code> field.</li>
|
||||
<li>A <code>OneToOneField</code> field.</li>
|
||||
<li>A reverse OneToOne relationship</li>
|
||||
<li>Any other "to-one" relationship.</li>
|
||||
</ul>
|
||||
<p>By default <code>RelatedField</code> will represent the target of the field using it's <code>__unicode__</code> method.</p>
|
||||
<p>You can customise this behaviour by subclassing <code>ManyRelatedField</code>, and overriding the <code>.to_native(self, value)</code> method.</p>
|
||||
<h2 id="manyrelatedfield">ManyRelatedField</h2>
|
||||
<p>This field can be applied to any of the following:</p>
|
||||
<ul>
|
||||
<li>A <code>ManyToManyField</code> field.</li>
|
||||
<li>A reverse ManyToMany relationship.</li>
|
||||
<li>A reverse ForeignKey relationship</li>
|
||||
<li>Any other "to-many" relationship.</li>
|
||||
</ul>
|
||||
<p>By default <code>ManyRelatedField</code> will represent the targets of the field using their <code>__unicode__</code> method.</p>
|
||||
<p>For example, given the following models:</p>
|
||||
<pre class="prettyprint lang-py"><code>class TaggedItem(models.Model):
|
||||
"""
|
||||
Tags arbitrary model instances using a generic relation.
|
||||
|
||||
See: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/
|
||||
"""
|
||||
tag = models.SlugField()
|
||||
content_type = models.ForeignKey(ContentType)
|
||||
object_id = models.PositiveIntegerField()
|
||||
content_object = GenericForeignKey('content_type', 'object_id')
|
||||
|
||||
def __unicode__(self):
|
||||
return self.tag
|
||||
|
||||
class Bookmark(models.Model):
|
||||
"""
|
||||
A bookmark consists of a URL, and 0 or more descriptive tags.
|
||||
"""
|
||||
url = models.URLField()
|
||||
tags = GenericRelation(TaggedItem)
|
||||
</code></pre>
|
||||
<p>And a model serializer defined like this:</p>
|
||||
<pre class="prettyprint lang-py"><code>class BookmarkSerializer(serializers.ModelSerializer):
|
||||
tags = serializers.ManyRelatedField(source='tags')
|
||||
|
||||
class Meta:
|
||||
model = Bookmark
|
||||
exclude = ('id',)
|
||||
</code></pre>
|
||||
<p>The an example output format for a Bookmark instance would be:</p>
|
||||
<pre class="prettyprint lang-py"><code>{
|
||||
'tags': [u'django', u'python'],
|
||||
'url': u'https://www.djangoproject.com/'
|
||||
}
|
||||
</code></pre>
|
||||
<h2 id="primarykeyrelatedfield">PrimaryKeyRelatedField</h2>
|
||||
<p>As with <code>RelatedField</code> field can be applied to any "to-one" relationship, such as a <code>ForeignKey</code> field.</p>
|
||||
<p><code>PrimaryKeyRelatedField</code> will represent the target of the field using it's primary key.</p>
|
||||
<p>Be default, <code>PrimaryKeyRelatedField</code> is read-write, although you can change this behaviour using the <code>readonly</code> flag.</p>
|
||||
<h2 id="manyprimarykeyrelatedfield">ManyPrimaryKeyRelatedField</h2>
|
||||
<p>As with <code>RelatedField</code> field can be applied to any "to-many" relationship, such as a <code>ManyToManyField</code> field, or a reverse <code>ForeignKey</code> relationship.</p>
|
||||
<p><code>PrimaryKeyRelatedField</code> will represent the target of the field using their primary key.</p>
|
||||
<p>Be default, <code>ManyPrimaryKeyRelatedField</code> is read-write, although you can change this behaviour using the <code>readonly</code> flag.</p>
|
||||
<h2 id="hyperlinkedrelatedfield">HyperlinkedRelatedField</h2>
|
||||
<h2 id="manyhyperlinkedrelatedfield">ManyHyperlinkedRelatedField</h2>
|
||||
<h2 id="hyperlinkedidentityfield">HyperLinkedIdentityField</h2>
|
||||
|
|
|
@ -121,8 +121,8 @@
|
|||
<li><a href="#jsonprenderer">JSONPRenderer</a></li>
|
||||
<li><a href="#yamlrenderer">YAMLRenderer</a></li>
|
||||
<li><a href="#xmlrenderer">XMLRenderer</a></li>
|
||||
<li><a href="#documentinghtmlrenderer">DocumentingHTMLRenderer</a></li>
|
||||
<li><a href="#htmltemplaterenderer">HTMLTemplateRenderer</a></li>
|
||||
<li><a href="#htmlrenderer">HTMLRenderer</a></li>
|
||||
<li><a href="#browsableapirenderer">BrowsableAPIRenderer</a></li>
|
||||
<li><a href="#custom-renderers">Custom renderers</a></li>
|
||||
<li class="main"><a href="#advanced-renderer-usage">Advanced renderer usage</a></li>
|
||||
<li><a href="#varying-behaviour-by-media-type">Varying behaviour by media type</a></li>
|
||||
|
@ -149,7 +149,7 @@
|
|||
<pre class="prettyprint lang-py"><code>REST_FRAMEWORK = {
|
||||
'DEFAULT_RENDERERS': (
|
||||
'rest_framework.renderers.YAMLRenderer',
|
||||
'rest_framework.renderers.DocumentingHTMLRenderer',
|
||||
'rest_framework.renderers.BrowsableAPIRenderer',
|
||||
)
|
||||
}
|
||||
</code></pre>
|
||||
|
@ -194,26 +194,51 @@ def user_count_view(request, format=None):
|
|||
<h2 id="xmlrenderer">XMLRenderer</h2>
|
||||
<p><strong>.media_type:</strong> <code>application/xml</code></p>
|
||||
<p><strong>.format:</strong> <code>'.xml'</code></p>
|
||||
<h2 id="documentinghtmlrenderer">DocumentingHTMLRenderer</h2>
|
||||
<p>Renders data into HTML for the browseable API. This renderer will determine which other renderer would have been given highest priority, and use that to display an API style response within the HTML page.</p>
|
||||
<p><strong>.media_type:</strong> <code>text/html</code></p>
|
||||
<p><strong>.format:</strong> <code>'.api'</code></p>
|
||||
<h2 id="htmltemplaterenderer">HTMLTemplateRenderer</h2>
|
||||
<h2 id="htmlrenderer">HTMLRenderer</h2>
|
||||
<p>Renders data to HTML, using Django's standard template rendering.
|
||||
Unlike other renderers, the data passed to the <code>Response</code> does not need to be serialized. Also, unlike other renderers, you may want to include a <code>template_name</code> argument when creating the <code>Response</code>.</p>
|
||||
<p>The HTMLTemplateRenderer will create a <code>RequestContext</code>, using the <code>response.data</code> as the context dict, and determine a template name to use to render the context.</p>
|
||||
<p>The HTMLRenderer will create a <code>RequestContext</code>, using the <code>response.data</code> as the context dict, and determine a template name to use to render the context.</p>
|
||||
<p>The template name is determined by (in order of preference):</p>
|
||||
<ol>
|
||||
<li>An explicit <code>.template_name</code> attribute set on the response.</li>
|
||||
<li>An explicit <code>.template_name</code> attribute set on this class.</li>
|
||||
<li>The return result of calling <code>view.get_template_names()</code>.</li>
|
||||
</ol>
|
||||
<p>You can use <code>HTMLTemplateRenderer</code> either to return regular HTML pages using REST framework, or to return both HTML and API responses from a single endpoint.</p>
|
||||
<p>If you're building websites that use <code>HTMLTemplateRenderer</code> along with other renderer classes, you should consider listing <code>HTMLTemplateRenderer</code> as the first class in the <code>renderer_classes</code> list, so that it will be prioritised first even for browsers that send poorly formed ACCEPT headers.</p>
|
||||
<p>An example of a view that uses <code>HTMLRenderer</code>:</p>
|
||||
<pre class="prettyprint lang-py"><code>class UserInstance(generics.RetrieveUserAPIView):
|
||||
"""
|
||||
A view that returns a templated HTML representations of a given user.
|
||||
"""
|
||||
model = Users
|
||||
renderer_classes = (HTMLRenderer,)
|
||||
|
||||
def get(self, request, *args, **kwargs)
|
||||
self.object = self.get_object()
|
||||
return Response(self.object, template_name='user_detail.html')
|
||||
</code></pre>
|
||||
<p>You can use <code>HTMLRenderer</code> either to return regular HTML pages using REST framework, or to return both HTML and API responses from a single endpoint.</p>
|
||||
<p>If you're building websites that use <code>HTMLRenderer</code> along with other renderer classes, you should consider listing <code>HTMLRenderer</code> as the first class in the <code>renderer_classes</code> list, so that it will be prioritised first even for browsers that send poorly formed <code>ACCEPT:</code> headers.</p>
|
||||
<p><strong>.media_type:</strong> <code>text/html</code></p>
|
||||
<p><strong>.format:</strong> <code>'.html'</code></p>
|
||||
<h2 id="browsableapirenderer">BrowsableAPIRenderer</h2>
|
||||
<p>Renders data into HTML for the Browseable API. This renderer will determine which other renderer would have been given highest priority, and use that to display an API style response within the HTML page.</p>
|
||||
<p><strong>.media_type:</strong> <code>text/html</code></p>
|
||||
<p><strong>.format:</strong> <code>'.api'</code></p>
|
||||
<h2 id="custom-renderers">Custom renderers</h2>
|
||||
<p>To implement a custom renderer, you should override <code>BaseRenderer</code>, set the <code>.media_type</code> and <code>.format</code> properties, and implement the <code>.render(self, data, media_type)</code> method.</p>
|
||||
<p>For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>from django.utils.encoding import smart_unicode
|
||||
from rest_framework import renderers
|
||||
|
||||
class PlainText(renderers.BaseRenderer):
|
||||
media_type = 'text/plain'
|
||||
format = 'txt'
|
||||
|
||||
def render(self, data, media_type):
|
||||
if isinstance(data, basestring):
|
||||
return data
|
||||
return smart_unicode(data)
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="advanced-renderer-usage">Advanced renderer usage</h1>
|
||||
<p>You can do some pretty flexible things using REST framework's renderers. Some examples...</p>
|
||||
|
@ -227,7 +252,7 @@ Unlike other renderers, the data passed to the <code>Response</code> does not ne
|
|||
<p>In some cases you might want your view to use different serialization styles depending on the accepted media type. If you need to do this you can access <code>request.accepted_renderer</code> to determine the negotiated renderer that will be used for the response.</p>
|
||||
<p>For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>@api_view(('GET',))
|
||||
@renderer_classes((TemplateHTMLRenderer, JSONRenderer))
|
||||
@renderer_classes((HTMLRenderer, JSONRenderer))
|
||||
def list_users(request):
|
||||
"""
|
||||
A view that can return JSON or HTML representations
|
||||
|
|
|
@ -151,7 +151,7 @@
|
|||
<ul>
|
||||
<li><code>data</code>: The serialized data for the response.</li>
|
||||
<li><code>status</code>: A status code for the response. Defaults to 200. See also <a href="status-codes">status codes</a>.</li>
|
||||
<li><code>template_name</code>: A template name to use if <code>HTMLTemplateRenderer</code> is selected.</li>
|
||||
<li><code>template_name</code>: A template name to use if <code>HTMLRenderer</code> is selected.</li>
|
||||
<li><code>headers</code>: A dictionary of HTTP headers to use in the response.</li>
|
||||
</ul>
|
||||
<h2 id="render">.render()</h2>
|
||||
|
@ -172,7 +172,7 @@ response['Cache-Control'] = 'no-cache'
|
|||
<h2 id="content">.content</h2>
|
||||
<p>The rendered content of the response. The <code>.render()</code> method must have been called before <code>.content</code> can be accessed.</p>
|
||||
<h2 id="template_name">.template_name</h2>
|
||||
<p>The <code>template_name</code>, if supplied. Only required if <code>HTMLTemplateRenderer</code> or some other custom template renderer is the accepted renderer for the reponse.</p>
|
||||
<p>The <code>template_name</code>, if supplied. Only required if <code>HTMLRenderer</code> or some other custom template renderer is the accepted renderer for the reponse.</p>
|
||||
<h2 id="accepted_renderer">.accepted_renderer</h2>
|
||||
<p>The renderer instance that will be used to render the response.</p>
|
||||
<p>Set automatically by the <code>APIView</code> or <code>@api_view</code> immediately before the response is returned from the view.</p>
|
||||
|
|
|
@ -138,8 +138,9 @@
|
|||
<p>REST framework provides two utility functions to make it more simple to return absolute URIs from your Web API.</p>
|
||||
<p>There's no requirement for you to use them, but if you do then the self-describing API will be able to automatically hyperlink it's output for you, which makes browsing the API much easier.</p>
|
||||
<h2 id="reverse">reverse</h2>
|
||||
<p><strong>Signature:</strong> <code>reverse(viewname, request, *args, **kwargs)</code></p>
|
||||
<p><strong>Signature:</strong> <code>reverse(viewname, *args, **kwargs)</code></p>
|
||||
<p>Has the same behavior as <a href="https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse"><code>django.core.urlresolvers.reverse</code></a>, except that it returns a fully qualified URL, using the request to determine the host and port.</p>
|
||||
<p>You should <strong>include the request as a keyword argument</strong> to the function, for example:</p>
|
||||
<pre class="prettyprint lang-py"><code>import datetime
|
||||
from rest_framework.utils import reverse
|
||||
from rest_framework.views import APIView
|
||||
|
@ -149,13 +150,16 @@ class APIRootView(APIView):
|
|||
year = datetime.datetime.now().year
|
||||
data = {
|
||||
...
|
||||
'year-summary-url': reverse('year-summary', request, args=[year])
|
||||
'year-summary-url': reverse('year-summary', args=[year], request=request)
|
||||
}
|
||||
return Response(data)
|
||||
</code></pre>
|
||||
<h2 id="reverse_lazy">reverse_lazy</h2>
|
||||
<p><strong>Signature:</strong> <code>reverse_lazy(viewname, request, *args, **kwargs)</code></p>
|
||||
<p><strong>Signature:</strong> <code>reverse_lazy(viewname, *args, **kwargs)</code></p>
|
||||
<p>Has the same behavior as <a href="https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse-lazy"><code>django.core.urlresolvers.reverse_lazy</code></a>, except that it returns a fully qualified URL, using the request to determine the host and port.</p>
|
||||
<p>As with the <code>reverse</code> function, you should <strong>include the request as a keyword argument</strong> to the function, for example:</p>
|
||||
<pre class="prettyprint lang-py"><code>api_root = reverse_lazy('api-root', request=request)
|
||||
</code></pre>
|
||||
</div><!--/span-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
|
|
|
@ -165,7 +165,7 @@ print api_settings.DEFAULT_AUTHENTICATION
|
|||
<p>Default:</p>
|
||||
<pre class="prettyprint lang-py"><code>(
|
||||
'rest_framework.renderers.JSONRenderer',
|
||||
'rest_framework.renderers.DocumentingHTMLRenderer'
|
||||
'rest_framework.renderers.BrowsableAPIRenderer'
|
||||
'rest_framework.renderers.TemplateHTMLRenderer'
|
||||
)
|
||||
</code></pre>
|
||||
|
|
|
@ -125,13 +125,13 @@
|
|||
<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 choosen with a view to making 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>First off, the disclaimer. The name "Django REST framework" was choosen 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>The following fall into the "required reading" category.</p>
|
||||
<ul>
|
||||
<li>Fielding's dissertation - <a href="http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm">Architectural Styles and
|
||||
<li>Roy Fielding's dissertation - <a href="http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm">Architectural Styles and
|
||||
the Design of Network-based Software Architectures</a>.</li>
|
||||
<li>Fielding's "<a href="http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven">REST APIs must be hypertext-driven</a>" blog post.</li>
|
||||
<li>Roy Fielding's "<a href="http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven">REST APIs must be hypertext-driven</a>" blog post.</li>
|
||||
<li>Leonard Richardson & Sam Ruby's <a href="">RESTful Web Services</a>.</li>
|
||||
<li>Mike Amundsen's <a href="…">Building Hypermedia APIs with HTML5 and Node</a>.</li>
|
||||
<li>Steve Klabnik's <a href="http://designinghypermediaapis.com/">Designing Hypermedia APIs</a>.</li>
|
||||
|
@ -144,7 +144,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 browseable 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>
|
||||
<h3 id="what-rest-framework-doesnt-provide">What REST framework <em>doesn't</em> provide.</h3>
|
||||
<p>What REST framework doesn't do is give you is machine readable hypermedia formats such as <a href="http://www.amundsen.com/media-types/collection/">Collection+JSON</a> or HTML <a href="http://microformats.org/wiki/Main_Page">microformats</a> by default, or the ability to auto-magically create HATEOAS style APIs. 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://www.amundsen.com/media-types/collection/">Collection+JSON</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 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-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
|
|
Loading…
Reference in New Issue
Block a user