| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
 | <!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 - Quickstart</title>
    <link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
    <link rel="canonical" href="http://django-rest-framework.org/tutorial/quickstart"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Django, API, REST, Quickstart">
    <meta name="author" content="Tom Christie">
    <!-- Le styles -->
    <link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
    <link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
    <link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
    <link href="http://django-rest-framework.org/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>
  </head>
  <body onload="prettyPrint()" class="quickstart-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 " href="../tutorial/1-serialization">Next <i class="icon-arrow-right icon-white"></i></a>
            <a class="repo-link btn btn-inverse btn-small " href="/"><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://django-rest-framework.org">Django REST framework</a>
          <div class="nav-collapse collapse">
            <ul class="nav">
              <li><a href="http://django-rest-framework.org">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://django-rest-framework.org/tutorial/quickstart">Quickstart</a></li>
                  <li><a href="http://django-rest-framework.org/tutorial/1-serialization">1 - Serialization</a></li>
                  <li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses">2 - Requests and responses</a></li>
                  <li><a href="http://django-rest-framework.org/tutorial/3-class-based-views">3 - Class based views</a></li>
                  <li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions">4 - Authentication and permissions</a></li>
                  <li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis">5 - Relationships and hyperlinked APIs</a></li>
                  <li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers">6 - Viewsets and routers</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://django-rest-framework.org/api-guide/requests">Requests</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/responses">Responses</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/views">Views</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/generic-views">Generic views</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/viewsets">Viewsets</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/routers">Routers</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/parsers">Parsers</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/renderers">Renderers</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/serializers">Serializers</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/fields">Serializer fields</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/relations">Serializer relations</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/authentication">Authentication</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/permissions">Permissions</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/throttling">Throttling</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/filtering">Filtering</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/pagination">Pagination</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/content-negotiation">Content negotiation</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/format-suffixes">Format suffixes</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/reverse">Returning URLs</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/exceptions">Exceptions</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/status-codes">Status codes</a></li>
                  <li><a href="http://django-rest-framework.org/api-guide/testing">Testing</a></li>
                  <li><a href="http://django-rest-framework.org/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://django-rest-framework.org/topics/documenting-your-api">Documenting your API</a></li>
                  <li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors">AJAX, CSRF & CORS</a></li>
                  <li><a href="http://django-rest-framework.org/topics/browser-enhancements">Browser enhancements</a></li>
                  <li><a href="http://django-rest-framework.org/topics/browsable-api">The Browsable API</a></li>
                  <li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas">REST, Hypermedia & HATEOAS</a></li>
                  <li><a href="http://django-rest-framework.org/topics/contributing">Contributing to REST framework</a></li>
                  <li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement">2.0 Announcement</a></li>
                  <li><a href="http://django-rest-framework.org/topics/2.2-announcement">2.2 Announcement</a></li>
                  <li><a href="http://django-rest-framework.org/topics/2.3-announcement">2.3 Announcement</a></li>
                  <li><a href="http://django-rest-framework.org/topics/release-notes">Release Notes</a></li>
                  <li><a href="http://django-rest-framework.org/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">
<!-- 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="#quickstart">Quickstart</a></li>
<li><a href="#project-setup">Project setup</a></li>
<li><a href="#serializers">Serializers</a></li>
<li><a href="#views">Views</a></li>
<li><a href="#urls">URLs</a></li>
<li><a href="#settings">Settings</a></li>
<li><a href="#testing-our-api">Testing our API</a></li>
              <div>
              <hr>
<p><strong>The team behind REST framework is launching a new API service.</strong></p>
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
<!-- Begin MailChimp Signup Form -->
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
<style type="text/css">
    #mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
    /* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
       We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
</style>
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
<!--     <label for="mce-EMAIL">Keep me posted!</label>
 -->    <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
    <div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
</form>
</div>
</style></div>
              </ul>
<!--End mc_embed_signup-->
            </div>
          </div>
          <div id="main-content" class="span9">
            <h1 id="quickstart">Quickstart</h1>
<p>We're going to create a simple API to allow admin users to view and edit the users and groups in the system.</p>
<h2 id="project-setup">Project setup</h2>
<p>Create a new Django project named <code>tutorial</code>, then start a new app called <code>quickstart</code>.</p>
<pre class="prettyprint lang-py"><code># Set up a new project
django-admin.py startproject tutorial
cd tutorial
# Create a virtualenv to isolate our package dependencies locally
virtualenv env
source env/bin/activate  # On Windows use `env\Scripts\activate`
# Install Django and Django REST framework into the virtualenv
pip install django
pip install djangorestframework
# Create a new app
python manage.py startapp quickstart
</code></pre>
<p>Next you'll need to get a database set up and synced.  If you just want to use SQLite for now, then you'll want to edit your <code>tutorial/settings.py</code> module to include something like this:</p>
<pre class="prettyprint lang-py"><code>DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': 'database.sql',
        'USER': '',
        'PASSWORD': '',
        'HOST': '',
        'PORT': ''
    }
}
</code></pre>
<p>The run <code>syncdb</code> like so:</p>
<pre class="prettyprint lang-py"><code>python manage.py syncdb
</code></pre>
<p>Once you've set up a database and got everything synced and ready to go, open up the app's directory and we'll get coding...</p>
<h2 id="serializers">Serializers</h2>
<p>First up we're going to define some serializers in <code>quickstart/serializers.py</code> that we'll use for our data representations.</p>
<pre class="prettyprint lang-py"><code>from django.contrib.auth.models import User, Group
from rest_framework import serializers
class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'username', 'email', 'groups')
class GroupSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Group
        fields = ('url', 'name')
</code></pre>
<p>Notice that we're using hyperlinked relations in this case, with <code>HyperlinkedModelSerializer</code>.  You can also use primary key and various other relationships, but hyperlinking is good RESTful design.</p>
<h2 id="views">Views</h2>
<p>Right, we'd better write some views then.  Open <code>quickstart/views.py</code> and get typing.</p>
<pre class="prettyprint lang-py"><code>from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from quickstart.serializers import UserSerializer, GroupSerializer
class UserViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer
class GroupViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows groups to be viewed or edited.
    """
    queryset = Group.objects.all()
    serializer_class = GroupSerializer
</code></pre>
<p>Rather than write multiple views we're grouping together all the common behavior into classes called <code>ViewSets</code>.</p>
<p>We can easily break these down into individual views if we need to, but using viewsets keeps the view logic nicely organized as well as being very concise.</p>
<p>Notice that our viewset classes here are a little different from those in the <a href="../#example">frontpage example</a>, as they include <code>queryset</code> and <code>serializer_class</code> attributes, instead of a <code>model</code> attribute.</p>
<p>For trivial cases you can simply set a <code>model</code> attribute on the <code>ViewSet</code> class and the serializer and queryset will be automatically generated for you.  Setting the <code>queryset</code> and/or <code>serializer_class</code> attributes gives you more explicit control of the API behaviour, and is the recommended style for most applications.</p>
<h2 id="urls">URLs</h2>
<p>Okay, now let's wire up the API URLs.  On to <code>tutorial/urls.py</code>...</p>
<pre class="prettyprint lang-py"><code>from django.conf.urls import patterns, url, include
from rest_framework import routers
from quickstart import views
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)
# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browseable API.
urlpatterns = patterns('',
    url(r'^', include(router.urls)),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
)
</code></pre>
<p>Because we're using viewsets instead of views, we can automatically generate the URL conf for our API, by simply registering the viewsets with a router class.</p>
<p>Again, if we need more control over the API URLs we can simply drop down to using regular class based views, and writing the URL conf explicitly.</p>
<p>Finally, we're including default login and logout views for use with the browsable API.  That's optional, but useful if your API requires authentication and you want to use the browsable API.</p>
<h2 id="settings">Settings</h2>
<p>We'd also like to set a few global settings.  We'd like to turn on pagination, and we want our API to only be accessible to admin users.  The settings module will be in <code>tutorial/settings.py</code></p>
<pre class="prettyprint lang-py"><code>INSTALLED_APPS = (
    ...
    'rest_framework',
)
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAdminUser',),
    'PAGINATE_BY': 10
}
</code></pre>
<p>Okay, we're done.</p>
<hr />
<h2 id="testing-our-api">Testing our API</h2>
<p>We're now ready to test the API we've built.  Let's fire up the server from the command line.</p>
<pre class="prettyprint lang-py"><code>python ./manage.py runserver
</code></pre>
<p>We can now access our API, both from the command-line, using tools like <code>curl</code>...</p>
<pre class="prettyprint lang-py"><code>bash: curl -H 'Accept: application/json; indent=4' -u admin:password http://127.0.0.1:8000/users/ 
{
    "count": 2, 
    "next": null, 
    "previous": null, 
    "results": [
        {
            "email": "admin@example.com", 
            "groups": [], 
            "url": "http://127.0.0.1:8000/users/1/", 
            "username": "admin"
        }, 
        {
            "email": "tom@example.com", 
            "groups": [                ], 
            "url": "http://127.0.0.1:8000/users/2/", 
            "username": "tom"
        }
    ]
}
</code></pre>
<p>Or directly through the browser...</p>
<p><img alt="Quick start image" src="../img/quickstart.png" /></p>
<p>Great, that was easy!</p>
<p>If you want to get a more in depth understanding of how REST framework fits together head on over to <a href="1-serialization">the tutorial</a>, or start browsing the <a href="../#api-guide">API guide</a>.</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://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
    <script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
    <script src="http://django-rest-framework.org/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>
 |