mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-12-04 23:44:07 +03:00
Latest docs build
This commit is contained in:
parent
3dd53f5bfe
commit
49ecd15735
165
api-guide/fields.html
Normal file
165
api-guide/fields.html
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Django REST framework</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="author" content="">
|
||||||
|
|
||||||
|
<!-- Le styles -->
|
||||||
|
<link href="http://tomchristie.github.com/django-rest-framework/css/prettify.css" rel="stylesheet">
|
||||||
|
<link href="http://tomchristie.github.com/django-rest-framework/css/bootstrap.css" rel="stylesheet">
|
||||||
|
<link href="http://tomchristie.github.com/django-rest-framework/css/bootstrap-responsive.css" rel="stylesheet">
|
||||||
|
<link href="http://tomchristie.github.com/django-rest-framework/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]-->
|
||||||
|
<body onload="prettyPrint()" class="fields-page">
|
||||||
|
|
||||||
|
<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/restframework2">GitHub</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://tomchristie.github.com/django-rest-framework">Django REST framework</a>
|
||||||
|
<div class="nav-collapse collapse">
|
||||||
|
<ul class="nav">
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework">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="http://tomchristie.github.com/django-rest-framework/tutorial/1-serialization">1 - Serialization</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/tutorial/2-requests-and-responses">2 - Requests and responses</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/tutorial/3-class-based-views">3 - Class based views</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/tutorial/4-authentication-permissions-and-throttling">4 - Authentication, permissions and throttling</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/tutorial/5-relationships-and-hyperlinked-apis">5 - Relationships and hyperlinked APIs</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/tutorial/6-resource-orientated-projects">6 - Resource orientated projects</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="dropdown">
|
||||||
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/requests">Requests</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/responses">Responses</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/views">Views</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/generic-views">Generic views</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/parsers">Parsers</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/renderers">Renderers</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/serializers">Serializers</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/authentication">Authentication</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/permissions">Permissions</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/throttling">Throttling</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/pagination">Pagination</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/content-negotiation">Content negotiation</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/format-suffixes">Format suffixes</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/reverse">Returning URLs</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/exceptions">Exceptions</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/status-codes">Status codes</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/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="http://tomchristie.github.com/django-rest-framework/topics/csrf">Working with AJAX and CSRF</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/topics/formoverloading">Browser based PUT, PATCH and DELETE</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/topics/browsable-api">Working with the browsable API</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/topics/contributing">Contributing to REST framework</a></li>
|
||||||
|
<li><a href="http://tomchristie.github.com/django-rest-framework/topics/credits">Credits</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul class="nav pull-right">
|
||||||
|
<li class="dropdown">
|
||||||
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Version: 2.0.0 <b class="caret"></b></a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a href="#">Trunk</a></li>
|
||||||
|
<li><a href="#">2.0.0</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div><!--/.nav-collapse -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="span3">
|
||||||
|
<div id="table-of-contents" class="well affix span3">
|
||||||
|
<ul class="nav nav-list side-nav">
|
||||||
|
<li class="main"><a href="#serializer-fields">Serializer fields</a></li>
|
||||||
|
<li class="main"><a href="#generic-fields">Generic Fields</a></li>
|
||||||
|
<li><a href="#field">Field</a></li>
|
||||||
|
<li><a href="#modelfield">ModelField</a></li>
|
||||||
|
<li class="main"><a href="#typed-fields">Typed Fields</a></li>
|
||||||
|
<li><a href="#booleanfield">BooleanField</a></li>
|
||||||
|
<li><a href="#charfield">CharField</a></li>
|
||||||
|
<li><a href="#emailfield">EmailField</a></li>
|
||||||
|
<li><a href="#datefield">DateField</a></li>
|
||||||
|
<li><a href="#datetimefield">DateTimeField</a></li>
|
||||||
|
<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="#primarykeyrelatedfield">PrimaryKeyRelatedField</a></li>
|
||||||
|
<li><a href="#manyprimarykeyrelatedfield">ManyPrimaryKeyRelatedField</a></li>
|
||||||
|
<li><a href="#hyperlinkedrelatedfield">HyperlinkedRelatedField</a></li>
|
||||||
|
<li><a href="#manyhyperlinkedrelatedfield">ManyHyperlinkedRelatedField</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="main-content" class="span9">
|
||||||
|
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/blob/restframework2/rest_framework/fields.py"><span class="label label-info">fields.py</span></a></p>
|
||||||
|
<h1 id="serializer-fields">Serializer fields</h1>
|
||||||
|
<blockquote>
|
||||||
|
<p>Flat is better than nested.</p>
|
||||||
|
<p>— <a href="http://www.python.org/dev/peps/pep-0020/">The Zen of Python</a></p>
|
||||||
|
</blockquote>
|
||||||
|
<h1 id="generic-fields">Generic Fields</h1>
|
||||||
|
<h2 id="field">Field</h2>
|
||||||
|
<h2 id="modelfield">ModelField</h2>
|
||||||
|
<h1 id="typed-fields">Typed Fields</h1>
|
||||||
|
<h2 id="booleanfield">BooleanField</h2>
|
||||||
|
<h2 id="charfield">CharField</h2>
|
||||||
|
<h2 id="emailfield">EmailField</h2>
|
||||||
|
<h2 id="datefield">DateField</h2>
|
||||||
|
<h2 id="datetimefield">DateTimeField</h2>
|
||||||
|
<h2 id="integerfield">IntegerField</h2>
|
||||||
|
<h2 id="floatfield">FloatField</h2>
|
||||||
|
<h1 id="relational-fields">Relational Fields</h1>
|
||||||
|
<p>Relational fields are used to represent model relationships.</p>
|
||||||
|
<h2 id="primarykeyrelatedfield">PrimaryKeyRelatedField</h2>
|
||||||
|
<h2 id="manyprimarykeyrelatedfield">ManyPrimaryKeyRelatedField</h2>
|
||||||
|
<h2 id="hyperlinkedrelatedfield">HyperlinkedRelatedField</h2>
|
||||||
|
<h2 id="manyhyperlinkedrelatedfield">ManyHyperlinkedRelatedField</h2>
|
||||||
|
</div><!--/span-->
|
||||||
|
</div><!--/row-->
|
||||||
|
</div><!--/.fluid-container-->
|
||||||
|
|
||||||
|
<!-- Le javascript
|
||||||
|
================================================== -->
|
||||||
|
<!-- Placed at the end of the document so the pages load faster -->
|
||||||
|
<script src="http://tomchristie.github.com/django-rest-framework/js/jquery-1.8.1-min.js"></script>
|
||||||
|
<script src="http://tomchristie.github.com/django-rest-framework/js/prettify.js"></script>
|
||||||
|
<script src="http://tomchristie.github.com/django-rest-framework/js/bootstrap-dropdown.js"></script>
|
||||||
|
<script src="http://tomchristie.github.com/django-rest-framework/js/bootstrap-scrollspy.js"></script>
|
||||||
|
<script src="http://tomchristie.github.com/django-rest-framework/js/bootstrap-collapse.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();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body></html>
|
|
@ -95,7 +95,7 @@
|
||||||
<div id="table-of-contents" class="well affix span3">
|
<div id="table-of-contents" class="well affix span3">
|
||||||
<ul class="nav nav-list side-nav">
|
<ul class="nav nav-list side-nav">
|
||||||
<li class="main"><a href="#generic-views">Generic views</a></li>
|
<li class="main"><a href="#generic-views">Generic views</a></li>
|
||||||
<li><a href="#example">Example</a></li>
|
<li><a href="#examples">Examples</a></li>
|
||||||
<li class="main"><a href="#api-reference">API Reference</a></li>
|
<li class="main"><a href="#api-reference">API Reference</a></li>
|
||||||
<li><a href="#listapiview">ListAPIView</a></li>
|
<li><a href="#listapiview">ListAPIView</a></li>
|
||||||
<li><a href="#listcreateapiview">ListCreateAPIView</a></li>
|
<li><a href="#listcreateapiview">ListCreateAPIView</a></li>
|
||||||
|
@ -111,7 +111,6 @@
|
||||||
<li><a href="#retrievemodelmixin">RetrieveModelMixin</a></li>
|
<li><a href="#retrievemodelmixin">RetrieveModelMixin</a></li>
|
||||||
<li><a href="#updatemodelmixin">UpdateModelMixin</a></li>
|
<li><a href="#updatemodelmixin">UpdateModelMixin</a></li>
|
||||||
<li><a href="#destroymodelmixin">DestroyModelMixin</a></li>
|
<li><a href="#destroymodelmixin">DestroyModelMixin</a></li>
|
||||||
<li><a href="#metadatamixin">MetadataMixin</a></li>
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -126,12 +125,37 @@
|
||||||
<p>— <a href="https://docs.djangoproject.com/en/dev/ref/class-based-views/#base-vs-generic-views">Django Documentation</a></p>
|
<p>— <a href="https://docs.djangoproject.com/en/dev/ref/class-based-views/#base-vs-generic-views">Django Documentation</a></p>
|
||||||
</blockquote>
|
</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 behaviour. REST framework takes advantage of this by providing a number of pre-built views that provide for commonly used patterns. </p>
|
||||||
<h2 id="example">Example</h2>
|
<p>The generic views provided by REST framework allow you to quickly build API views that map closely to your database models.</p>
|
||||||
<p>...</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>
|
||||||
|
<p>Typically when using the generic views, you'll override the view, and set several class attributes.</p>
|
||||||
|
<pre class="prettyprint lang-py"><code>class UserList(generics.ListCreateAPIView):
|
||||||
|
serializer = UserSerializer
|
||||||
|
model = User
|
||||||
|
permissions = (IsAdminUser,)
|
||||||
|
paginate_by = 100
|
||||||
|
</code></pre>
|
||||||
|
<p>For more complex cases you might also want to override various methods on the view class. For example.</p>
|
||||||
|
<pre class="prettyprint lang-py"><code>class UserList(generics.ListCreateAPIView):
|
||||||
|
serializer = UserSerializer
|
||||||
|
model = User
|
||||||
|
permissions = (IsAdminUser,)
|
||||||
|
|
||||||
|
def get_paginate_by(self):
|
||||||
|
"""
|
||||||
|
Use smaller pagination for HTML representations.
|
||||||
|
"""
|
||||||
|
if self.request.accepted_media_type == 'text/html':
|
||||||
|
return 10
|
||||||
|
return 100
|
||||||
|
</code></pre>
|
||||||
|
<p>For very simple cases you might want to pass through any class attributes using the <code>.as_view()</code> method. For example, your URLconf might include something the following entry.</p>
|
||||||
|
<pre class="prettyprint lang-py"><code>url(r'^/users/', ListCreateAPIView.as_view(model=User) name='user-list')
|
||||||
|
</code></pre>
|
||||||
<hr />
|
<hr />
|
||||||
<h1 id="api-reference">API Reference</h1>
|
<h1 id="api-reference">API Reference</h1>
|
||||||
<h2 id="listapiview">ListAPIView</h2>
|
<h2 id="listapiview">ListAPIView</h2>
|
||||||
<p>Used for read-write endpoints to represent a collection of model instances.</p>
|
<p>Used for read-only endpoints to represent a collection of model instances.</p>
|
||||||
<p>Provides a <code>get</code> method handler.</p>
|
<p>Provides a <code>get</code> method handler.</p>
|
||||||
<h2 id="listcreateapiview">ListCreateAPIView</h2>
|
<h2 id="listcreateapiview">ListCreateAPIView</h2>
|
||||||
<p>Used for read-write endpoints to represent a collection of model instances.</p>
|
<p>Used for read-write endpoints to represent a collection of model instances.</p>
|
||||||
|
@ -144,6 +168,7 @@
|
||||||
<p>Provides <code>get</code>, <code>put</code> and <code>delete</code> method handlers.</p>
|
<p>Provides <code>get</code>, <code>put</code> and <code>delete</code> method handlers.</p>
|
||||||
<hr />
|
<hr />
|
||||||
<h1 id="base-views">Base views</h1>
|
<h1 id="base-views">Base views</h1>
|
||||||
|
<p>Each of the generic views provided is built by combining one of the base views below, with one or more mixin classes.</p>
|
||||||
<h2 id="baseapiview">BaseAPIView</h2>
|
<h2 id="baseapiview">BaseAPIView</h2>
|
||||||
<p>Extends REST framework's <code>APIView</code> class, adding support for serialization of model instances and model querysets.</p>
|
<p>Extends REST framework's <code>APIView</code> class, adding support for serialization of model instances and model querysets.</p>
|
||||||
<h2 id="multipleobjectbaseapiview">MultipleObjectBaseAPIView</h2>
|
<h2 id="multipleobjectbaseapiview">MultipleObjectBaseAPIView</h2>
|
||||||
|
@ -154,7 +179,7 @@
|
||||||
<p><strong>See also:</strong> ccbv.co.uk documentation for <a href="http://ccbv.co.uk/projects/Django/1.4/django.views.generic.detail/SingleObjectMixin/">SingleObjectMixin</a>.</p>
|
<p><strong>See also:</strong> ccbv.co.uk documentation for <a href="http://ccbv.co.uk/projects/Django/1.4/django.views.generic.detail/SingleObjectMixin/">SingleObjectMixin</a>.</p>
|
||||||
<hr />
|
<hr />
|
||||||
<h1 id="mixins">Mixins</h1>
|
<h1 id="mixins">Mixins</h1>
|
||||||
<p>The mixin classes provide the actions that are used </p>
|
<p>The mixin classes provide the actions that are used to provide the basic view behaviour. Note that the mixin classes provide action methods rather than defining the handler methods such as <code>.get()</code> and <code>.post()</code> directly. This allows for more flexible composition of behaviour. </p>
|
||||||
<h2 id="listmodelmixin">ListModelMixin</h2>
|
<h2 id="listmodelmixin">ListModelMixin</h2>
|
||||||
<p>Provides a <code>.list(request, *args, **kwargs)</code> method, that implements listing a queryset.</p>
|
<p>Provides a <code>.list(request, *args, **kwargs)</code> method, that implements listing a queryset.</p>
|
||||||
<h2 id="createmodelmixin">CreateModelMixin</h2>
|
<h2 id="createmodelmixin">CreateModelMixin</h2>
|
||||||
|
@ -165,8 +190,6 @@
|
||||||
<p>Provides a <code>.update(request, *args, **kwargs)</code> method, that implements updating and saving an existing model instance.</p>
|
<p>Provides a <code>.update(request, *args, **kwargs)</code> method, that implements updating and saving an existing model instance.</p>
|
||||||
<h2 id="destroymodelmixin">DestroyModelMixin</h2>
|
<h2 id="destroymodelmixin">DestroyModelMixin</h2>
|
||||||
<p>Provides a <code>.destroy(request, *args, **kwargs)</code> method, that implements deletion of an existing model instance.</p>
|
<p>Provides a <code>.destroy(request, *args, **kwargs)</code> method, that implements deletion of an existing model instance.</p>
|
||||||
<h2 id="metadatamixin">MetadataMixin</h2>
|
|
||||||
<p>Provides a <code>.metadata(request, *args, **kwargs)</code> method, that returns a response containing metadata about the view.</p>
|
|
||||||
</div><!--/span-->
|
</div><!--/span-->
|
||||||
</div><!--/row-->
|
</div><!--/row-->
|
||||||
</div><!--/.fluid-container-->
|
</div><!--/.fluid-container-->
|
||||||
|
|
|
@ -291,6 +291,9 @@ The <code>ModelSerializer</code> class lets you automatically create a Serialize
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Account
|
model = Account
|
||||||
|
|
||||||
|
def get_pk_field(self, model_field):
|
||||||
|
return Field(readonly=True)
|
||||||
|
|
||||||
def get_nested_field(self, model_field):
|
def get_nested_field(self, model_field):
|
||||||
return ModelSerializer()
|
return ModelSerializer()
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,7 @@
|
||||||
<li><a href="#form_content_override">FORM_CONTENT_OVERRIDE</a></li>
|
<li><a href="#form_content_override">FORM_CONTENT_OVERRIDE</a></li>
|
||||||
<li><a href="#form_contenttype_override">FORM_CONTENTTYPE_OVERRIDE</a></li>
|
<li><a href="#form_contenttype_override">FORM_CONTENTTYPE_OVERRIDE</a></li>
|
||||||
<li><a href="#url_accept_override">URL_ACCEPT_OVERRIDE</a></li>
|
<li><a href="#url_accept_override">URL_ACCEPT_OVERRIDE</a></li>
|
||||||
|
<li><a href="#url_format_override">URL_FORMAT_OVERRIDE</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -202,7 +203,9 @@ print api_settings.DEFAULT_AUTHENTICATION
|
||||||
<h2 id="url_accept_override">URL_ACCEPT_OVERRIDE</h2>
|
<h2 id="url_accept_override">URL_ACCEPT_OVERRIDE</h2>
|
||||||
<p>The name of a URL parameter that may be used to override the HTTP <code>Accept</code> header.</p>
|
<p>The name of a URL parameter that may be used to override the HTTP <code>Accept</code> header.</p>
|
||||||
<p>If the value of this setting is <code>None</code> then URL accept overloading will be disabled.</p>
|
<p>If the value of this setting is <code>None</code> then URL accept overloading will be disabled.</p>
|
||||||
<p>Default: <code>'_accept'</code></p>
|
<p>Default: <code>'accept'</code></p>
|
||||||
|
<h2 id="url_format_override">URL_FORMAT_OVERRIDE</h2>
|
||||||
|
<p>Default: <code>'format'</code></p>
|
||||||
</div><!--/span-->
|
</div><!--/span-->
|
||||||
</div><!--/row-->
|
</div><!--/row-->
|
||||||
</div><!--/.fluid-container-->
|
</div><!--/.fluid-container-->
|
||||||
|
|
|
@ -111,7 +111,7 @@
|
||||||
<div id="main-content" class="span9">
|
<div id="main-content" class="span9">
|
||||||
<iframe src="http://ghbtns.com/github-btn.html?user=tomchristie&repo=django-rest-framework&type=watch&count=true" allowtransparency="true" frameborder="0" scrolling="0" width="110px" height="20px"></iframe>
|
<iframe src="http://ghbtns.com/github-btn.html?user=tomchristie&repo=django-rest-framework&type=watch&count=true" allowtransparency="true" frameborder="0" scrolling="0" width="110px" height="20px"></iframe>
|
||||||
|
|
||||||
<p><a href="http://travis-ci.org/tomchristie/django-rest-framework?branch=restframework2"><img alt="Build Status" src="https://secure.travis-ci.org/tomchristie/django-rest-framework.png?branch=restframework2" /></a></p>
|
<p><a href="http://travis-ci.org/tomchristie/django-rest-framework?branch=restframework2">![travis-build-image]</a></p>
|
||||||
<h1 id="django-rest-framework">Django REST framework</h1>
|
<h1 id="django-rest-framework">Django REST framework</h1>
|
||||||
<p><strong>A toolkit for building well-connected, self-describing Web APIs.</strong></p>
|
<p><strong>A toolkit for building well-connected, self-describing Web APIs.</strong></p>
|
||||||
<p><strong>WARNING: This documentation is for the 2.0 redesign of REST framework. It is a work in progress.</strong></p>
|
<p><strong>WARNING: This documentation is for the 2.0 redesign of REST framework. It is a work in progress.</strong></p>
|
||||||
|
|
|
@ -94,9 +94,11 @@
|
||||||
<div class="span3">
|
<div class="span3">
|
||||||
<div id="table-of-contents" class="well affix span3">
|
<div id="table-of-contents" class="well affix span3">
|
||||||
<ul class="nav nav-list side-nav">
|
<ul class="nav nav-list side-nav">
|
||||||
<li class="main"><a href="#browser-based-put-&-delete">Browser based PUT & DELETE</a></li>
|
<li class="main"><a href="#browser-hacks">Browser hacks</a></li>
|
||||||
<li><a href="#overloading-the-http-method">Overloading the HTTP method</a></li>
|
<li><a href="#browser-based-put,-delete,-etc">Browser based PUT, DELETE, etc...</a></li>
|
||||||
<li><a href="#overloading-the-http-content-type">Overloading the HTTP content type</a></li>
|
<li><a href="#browser-based-submission-of-non-form-content">Browser based submission of non-form content</a></li>
|
||||||
|
<li><a href="#url-based-accept-headers">URL based accept headers</a></li>
|
||||||
|
<li><a href="#url-based-format-suffixes">URL based format suffixes</a></li>
|
||||||
<li><a href="#doesnt-html5-support-put-and-delete-forms">Doesn't HTML5 support PUT and DELETE forms?</a></li>
|
<li><a href="#doesnt-html5-support-put-and-delete-forms">Doesn't HTML5 support PUT and DELETE forms?</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -104,12 +106,12 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="main-content" class="span9">
|
<div id="main-content" class="span9">
|
||||||
<h1 id="browser-based-put-delete">Browser based PUT & DELETE</h1>
|
<h1 id="browser-hacks">Browser hacks</h1>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<p>"There are two noncontroversial uses for overloaded POST. The first is to <em>simulate</em> HTTP's uniform interface for clients like web browsers that don't support PUT or DELETE"</p>
|
<p>"There are two noncontroversial uses for overloaded POST. The first is to <em>simulate</em> HTTP's uniform interface for clients like web browsers that don't support PUT or DELETE"</p>
|
||||||
<p>— <a href="1">RESTful Web Services</a>, Leonard Richardson & Sam Ruby.</p>
|
<p>— <a href="1">RESTful Web Services</a>, Leonard Richardson & Sam Ruby.</p>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
<h2 id="overloading-the-http-method">Overloading the HTTP method</h2>
|
<h2 id="browser-based-put-delete-etc">Browser based PUT, DELETE, etc...</h2>
|
||||||
<p><strong>TODO: Preamble.</strong> Note that this is the same strategy as is used in <a href="2">Ruby on Rails</a>.</p>
|
<p><strong>TODO: Preamble.</strong> Note that this is the same strategy as is used in <a href="2">Ruby on Rails</a>.</p>
|
||||||
<p>For example, given the following form:</p>
|
<p>For example, given the following form:</p>
|
||||||
<pre class="prettyprint lang-py"><code><form action="/news-items/5" method="POST">
|
<pre class="prettyprint lang-py"><code><form action="/news-items/5" method="POST">
|
||||||
|
@ -117,7 +119,7 @@
|
||||||
</form>
|
</form>
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<p><code>request.method</code> would return <code>"DELETE"</code>.</p>
|
<p><code>request.method</code> would return <code>"DELETE"</code>.</p>
|
||||||
<h2 id="overloading-the-http-content-type">Overloading the HTTP content type</h2>
|
<h2 id="browser-based-submission-of-non-form-content">Browser based submission of non-form content</h2>
|
||||||
<p>Browser-based submission of content types other than form are supported by using form fields named <code>_content</code> and <code>_content_type</code>:</p>
|
<p>Browser-based submission of content types other than form are supported by using form fields named <code>_content</code> and <code>_content_type</code>:</p>
|
||||||
<p>For example, given the following form:</p>
|
<p>For example, given the following form:</p>
|
||||||
<pre class="prettyprint lang-py"><code><form action="/news-items/5" method="PUT">
|
<pre class="prettyprint lang-py"><code><form action="/news-items/5" method="PUT">
|
||||||
|
@ -126,10 +128,10 @@
|
||||||
</form>
|
</form>
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<p><code>request.content_type</code> would return <code>"application/json"</code>, and <code>request.content</code> would return <code>"{'count': 1}"</code></p>
|
<p><code>request.content_type</code> would return <code>"application/json"</code>, and <code>request.content</code> would return <code>"{'count': 1}"</code></p>
|
||||||
<h2 id="why-not-just-use-javascript">Why not just use Javascript?</h2>
|
<h2 id="url-based-accept-headers">URL based accept headers</h2>
|
||||||
<p><strong>[TODO]</strong></p>
|
<h2 id="url-based-format-suffixes">URL based format suffixes</h2>
|
||||||
<h2 id="doesnt-html5-support-put-and-delete-forms">Doesn't HTML5 support PUT and DELETE forms?</h2>
|
<h2 id="doesnt-html5-support-put-and-delete-forms">Doesn't HTML5 support PUT and DELETE forms?</h2>
|
||||||
<p>Nope. It was at one point intended to support <code>PUT</code> and <code>DELETE</code> forms, but was later <a href="3">dropped from the spec</a>. There remains <a href="4">ongoing discussion</a> about adding support for <code>PUT</code> and <code>DELETE</code>, as well as how to support content-types other than form-encoded data.</p>
|
<p>Nope. It was at one point intended to support <code>PUT</code> and <code>DELETE</code> forms, but was later <a href="3">dropped from the spec</a>. There remains <a href="4">ongoing discussion</a> about adding support for <code>PUT</code> and <code>DELETE</code>, as well as how to support content types other than form-encoded data.</p>
|
||||||
</div><!--/span-->
|
</div><!--/span-->
|
||||||
</div><!--/row-->
|
</div><!--/row-->
|
||||||
</div><!--/.fluid-container-->
|
</div><!--/.fluid-container-->
|
||||||
|
|
|
@ -172,7 +172,7 @@ class Comment(models.Model):
|
||||||
<pre class="prettyprint lang-py"><code>python manage.py syncdb
|
<pre class="prettyprint lang-py"><code>python manage.py syncdb
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<h2 id="creating-a-serializer-class">Creating a Serializer class</h2>
|
<h2 id="creating-a-serializer-class">Creating a Serializer class</h2>
|
||||||
<p>We're going to create a simple Web API that we can use to edit these comment objects with. The first thing we need is a way of serializing and deserializing the objects into representations such as <code>json</code>. We do this by declaring serializers, that work very similarly to Django's forms. Create a file in the project named <code>serializers.py</code> and add the following.</p>
|
<p>We're going to create a simple Web API that we can use to edit these comment objects with. The first thing we need is a way of serializing and deserializing the objects into representations such as <code>json</code>. We do this by declaring serializers that work very similarly to Django's forms. Create a file in the project named <code>serializers.py</code> and add the following.</p>
|
||||||
<pre class="prettyprint lang-py"><code>from blog import models
|
<pre class="prettyprint lang-py"><code>from blog import models
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
@ -277,7 +277,7 @@ def comment_root(request):
|
||||||
return JSONResponse(serializer.errors, status=400)
|
return JSONResponse(serializer.errors, status=400)
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<p>Note that because we want to be able to POST to this view from clients that won't have a CSRF token we need to mark the view as <code>csrf_exempt</code>. This isn't something that you'd normally want to do, and REST framework views actually use more sensible behavior than this, but it'll do for our purposes right now. </p>
|
<p>Note that because we want to be able to POST to this view from clients that won't have a CSRF token we need to mark the view as <code>csrf_exempt</code>. This isn't something that you'd normally want to do, and REST framework views actually use more sensible behavior than this, but it'll do for our purposes right now. </p>
|
||||||
<p>We'll also need a view which corrosponds to an individual comment, and can be used to retrieve, update or delete the comment.</p>
|
<p>We'll also need a view which corresponds to an individual comment, and can be used to retrieve, update or delete the comment.</p>
|
||||||
<pre class="prettyprint lang-py"><code>@csrf_exempt
|
<pre class="prettyprint lang-py"><code>@csrf_exempt
|
||||||
def comment_instance(request, pk):
|
def comment_instance(request, pk):
|
||||||
"""
|
"""
|
||||||
|
@ -306,7 +306,7 @@ def comment_instance(request, pk):
|
||||||
comment.delete()
|
comment.delete()
|
||||||
return HttpResponse(status=204)
|
return HttpResponse(status=204)
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<p>Finally we need to wire these views up, in the <code>tutorial/urls.py</code> file.</p>
|
<p>Finally we need to wire these views up. Create the <code>blog/urls.py</code> file:</p>
|
||||||
<pre class="prettyprint lang-py"><code>from django.conf.urls import patterns, url
|
<pre class="prettyprint lang-py"><code>from django.conf.urls import patterns, url
|
||||||
|
|
||||||
urlpatterns = patterns('blog.views',
|
urlpatterns = patterns('blog.views',
|
||||||
|
|
|
@ -129,7 +129,7 @@ request.DATA # Handles arbitrary data. Works any HTTP request with content.
|
||||||
<li>The <code>@api_view</code> decorator for working with function based views.</li>
|
<li>The <code>@api_view</code> decorator for working with function based views.</li>
|
||||||
<li>The <code>APIView</code> class for working with class based views.</li>
|
<li>The <code>APIView</code> class for working with class based views.</li>
|
||||||
</ol>
|
</ol>
|
||||||
<p>These wrappers provide a few bits of functionality such as making sure you recieve <code>Request</code> instances in your view, and adding context to <code>Response</code> objects so that content negotiation can be performed.</p>
|
<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>
|
<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>Okay, let's go ahead and start using these new components to write a few views. </p>
|
||||||
|
@ -208,7 +208,7 @@ urlpatterns = patterns('blogpost.views',
|
||||||
|
|
||||||
urlpatterns = format_suffix_patterns(urlpatterns)
|
urlpatterns = format_suffix_patterns(urlpatterns)
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<p>We don't necessarily need to add these extra url patterns in, but it gives us a simple, clean way of refering to a specific format.</p>
|
<p>We don't necessarily need to add these extra url patterns in, but it gives us a simple, clean way of referring to a specific format.</p>
|
||||||
<h2 id="hows-it-looking">How's it looking?</h2>
|
<h2 id="hows-it-looking">How's it looking?</h2>
|
||||||
<p>Go ahead and test the API from the command line, as we did in <a href="1-serialization">tutorial part 1</a>. Everything is working pretty similarly, although we've got some nicer error handling if we send invalid requests.</p>
|
<p>Go ahead and test the API from the command line, as we did in <a href="1-serialization">tutorial part 1</a>. Everything is working pretty similarly, although we've got some nicer error handling if we send invalid requests.</p>
|
||||||
<p><strong>TODO: Describe using accept headers, content-type headers, and format suffixed URLs</strong></p>
|
<p><strong>TODO: Describe using accept headers, content-type headers, and format suffixed URLs</strong></p>
|
||||||
|
|
|
@ -129,10 +129,10 @@ class CommentRoot(APIView):
|
||||||
if serializer.is_valid():
|
if serializer.is_valid():
|
||||||
comment = serializer.object
|
comment = serializer.object
|
||||||
comment.save()
|
comment.save()
|
||||||
return Response(serializer.serialized, status=status.HTTP_201_CREATED)
|
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||||
return Response(serializer.serialized_errors, status=status.HTTP_400_BAD_REQUEST)
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<p>So far, so good. It looks pretty similar to the previous case, but we've got better seperation between the different HTTP methods. We'll also need to update the instance view. </p>
|
<p>So far, so good. It looks pretty similar to the previous case, but we've got better separation between the different HTTP methods. We'll also need to update the instance view. </p>
|
||||||
<pre class="prettyprint lang-py"><code>class CommentInstance(APIView):
|
<pre class="prettyprint lang-py"><code>class CommentInstance(APIView):
|
||||||
"""
|
"""
|
||||||
Retrieve, update or delete a comment instance.
|
Retrieve, update or delete a comment instance.
|
||||||
|
@ -223,15 +223,15 @@ class CommentRoot(mixins.ListModelMixin,
|
||||||
from blog.serializers import CommentSerializer
|
from blog.serializers import CommentSerializer
|
||||||
from rest_framework import generics
|
from rest_framework import generics
|
||||||
|
|
||||||
class CommentRoot(generics.RootAPIView):
|
class CommentRoot(generics.ListCreateAPIView):
|
||||||
model = Comment
|
model = Comment
|
||||||
serializer_class = CommentSerializer
|
serializer_class = CommentSerializer
|
||||||
|
|
||||||
class CommentInstance(generics.InstanceAPIView):
|
class CommentInstance(generics.RetrieveUpdateDestroyAPIView):
|
||||||
model = Comment
|
model = Comment
|
||||||
serializer_class = CommentSerializer
|
serializer_class = CommentSerializer
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<p>Wow, that's pretty concise. We've got a huge amount for free, and our code looks like good, clean, idomatic Django.</p>
|
<p>Wow, that's pretty concise. We've got a huge amount for free, and our code looks like good, clean, idiomatic Django.</p>
|
||||||
<p>Next we'll move onto <a href="4-authentication-permissions-and-throttling">part 4 of the tutorial</a>, where we'll take a look at how we can customize the behavior of our views to support a range of authentication, permissions, throttling and other aspects.</p>
|
<p>Next we'll move onto <a href="4-authentication-permissions-and-throttling">part 4 of the tutorial</a>, where we'll take a look at how we can customize the behavior of our views to support a range of authentication, permissions, throttling and other aspects.</p>
|
||||||
</div><!--/span-->
|
</div><!--/span-->
|
||||||
</div><!--/row-->
|
</div><!--/row-->
|
||||||
|
|
|
@ -110,8 +110,8 @@
|
||||||
<p>Resource classes are just View classes that don't have any handler methods bound to them. The actions on a resource are defined, </p>
|
<p>Resource classes are just View classes that don't have any handler methods bound to them. The actions on a resource are defined, </p>
|
||||||
<p>This allows us to:</p>
|
<p>This allows us to:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Encapsulate common behaviour accross a class of views, in a single Resource class.</li>
|
<li>Encapsulate common behaviour across a class of views, in a single Resource class.</li>
|
||||||
<li>Seperate out the actions of a Resource from the specfics of how those actions should be bound to a particular set of URLs.</li>
|
<li>Separate out the actions of a Resource from the specfics of how those actions should be bound to a particular set of URLs.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2 id="refactoring-to-use-resources-not-views">Refactoring to use Resources, not Views</h2>
|
<h2 id="refactoring-to-use-resources-not-views">Refactoring to use Resources, not Views</h2>
|
||||||
<p>For instance, we can re-write our 4 sets of views into something more compact...</p>
|
<p>For instance, we can re-write our 4 sets of views into something more compact...</p>
|
||||||
|
@ -158,7 +158,7 @@ router.register(resources.CommentResource)
|
||||||
urlpatterns = router.urlpatterns
|
urlpatterns = router.urlpatterns
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<h2 id="trade-offs-between-views-vs-resources">Trade-offs between views vs resources.</h2>
|
<h2 id="trade-offs-between-views-vs-resources">Trade-offs between views vs resources.</h2>
|
||||||
<p>Writing resource-orientated code can be a good thing. It helps ensure that URL conventions will be consistent across your APIs, and minimises the amount of code you need to write.</p>
|
<p>Writing resource-oriented code can be a good thing. It helps ensure that URL conventions will be consistent across your APIs, and minimises the amount of code you need to write.</p>
|
||||||
<p>The trade-off is that the behaviour is less explict. It can be more difficult to determine what code path is being followed, or where to override some behaviour.</p>
|
<p>The trade-off is that the behaviour is less explict. It can be more difficult to determine what code path is being followed, or where to override some behaviour.</p>
|
||||||
<h2 id="onwards-and-upwards">Onwards and upwards.</h2>
|
<h2 id="onwards-and-upwards">Onwards and upwards.</h2>
|
||||||
<p>We've reached the end of our tutorial. If you want to get more involved in the REST framework project, here's a few places you can start:</p>
|
<p>We've reached the end of our tutorial. If you want to get more involved in the REST framework project, here's a few places you can start:</p>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user