django-rest-framework/tutorial/6-resource-orientated-projects.html
2012-10-17 13:50:08 +01:00

218 lines
13 KiB
HTML

<!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>
<link href="http://tomchristie.github.com/django-rest-framework/img/favicon.ico" rel="icon" type="image/x-icon">
<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="6-resource-orientated-projects-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/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/quickstart">Quickstart</a></li>
<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/fields">Serializer fields</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/browser-enhancements">Browser enhancements</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/topics/browsable-api">The Browsable API</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/topics/rest-hypermedia-hateoas">REST, Hypermedia & HATEOAS</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/migration">2.0 Migration Guide</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/topics/release-notes">Release Notes</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">
<!-- TODO
<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="body-content">
<div class="container-fluid">
<div class="row-fluid">
<div class="span3">
<!-- TODO
<p style="margin-top: -12px">
<a class="btn btn-mini btn-primary" style="width: 60px">&laquo; previous</a>
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next &raquo;</a>
</p>
-->
<div id="table-of-contents">
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
<li class="main"><a href="#tutorial-6---resources">Tutorial 6 - Resources</a></li>
<li><a href="#refactoring-to-use-resources,-not-views">Refactoring to use Resources, not Views</a></li>
<li><a href="#binding-resources-to-urls-explicitly">Binding Resources to URLs explicitly</a></li>
<li><a href="#using-routers">Using Routers</a></li>
<li><a href="#trade-offs-between-views-vs-resources">Trade-offs between views vs resources.</a></li>
<li><a href="#onwards-and-upwards">Onwards and upwards.</a></li>
</ul>
</div>
</div>
<div id="main-content" class="span9">
<h1 id="tutorial-6-resources">Tutorial 6 - Resources</h1>
<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>
<ul>
<li>Encapsulate common behaviour across a class of views, in a single Resource class.</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>
<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>resources.py</p>
<pre class="prettyprint lang-py"><code>class BlogPostResource(ModelResource):
serializer_class = BlogPostSerializer
model = BlogPost
permissions_classes = (permissions.IsAuthenticatedOrReadOnly,)
throttle_classes = (throttles.UserRateThrottle,)
class CommentResource(ModelResource):
serializer_class = CommentSerializer
model = Comment
permissions_classes = (permissions.IsAuthenticatedOrReadOnly,)
throttle_classes = (throttles.UserRateThrottle,)
</code></pre>
<h2 id="binding-resources-to-urls-explicitly">Binding Resources to URLs explicitly</h2>
<p>The handler methods only get bound to the actions when we define the URLConf. Here's our urls.py:</p>
<pre class="prettyprint lang-py"><code>comment_root = CommentResource.as_view(actions={
'get': 'list',
'post': 'create'
})
comment_instance = CommentInstance.as_view(actions={
'get': 'retrieve',
'put': 'update',
'delete': 'destroy'
})
... # And for blog post
urlpatterns = patterns('blogpost.views',
url(r'^$', comment_root),
url(r'^(?P&lt;pk&gt;[0-9]+)$', comment_instance)
... # And for blog post
)
</code></pre>
<h2 id="using-routers">Using Routers</h2>
<p>Right now that hasn't really saved us a lot of code. However, now that we're using Resources rather than Views, we actually don't need to design the urlconf ourselves. The conventions for wiring up resources into views and urls can be handled automatically, using <code>Router</code> classes. All we need to do is register the appropriate resources with a router, and let it do the rest. Here's our re-wired <code>urls.py</code> file.</p>
<pre class="prettyprint lang-py"><code>from blog import resources
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(resources.BlogPostResource)
router.register(resources.CommentResource)
urlpatterns = router.urlpatterns
</code></pre>
<h2 id="trade-offs-between-views-vs-resources">Trade-offs between views vs resources.</h2>
<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>
<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>
<ul>
<li>Contribute on GitHub by reviewing issues, and submitting issues or pull requests.</li>
<li>Join the REST framework group, and help build the community.</li>
<li>Follow me <a href="https://twitter.com/_tomchristie">on Twitter</a> and say hi.</li>
</ul>
<p><strong>Now go build some awesome things.</strong></p>
</div><!--/span-->
</div><!--/row-->
</div><!--/.fluid-container-->
</div><!--/.body content-->
<div id="push"></div>
</div><!--/.wrapper -->
<footer class="span12">
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
</footer>
<!-- 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-1.0.js"></script>
<script src="http://tomchristie.github.com/django-rest-framework/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();
});
</script>
</body></html>