aboutsummaryrefslogtreecommitdiffstats
path: root/docs/tutorial
diff options
context:
space:
mode:
Diffstat (limited to 'docs/tutorial')
-rw-r--r--docs/tutorial/1-serialization.md94
-rw-r--r--docs/tutorial/2-requests-and-responses.md57
-rw-r--r--docs/tutorial/4-authentication-and-permissions.md24
-rw-r--r--docs/tutorial/5-relationships-and-hyperlinked-apis.md2
-rw-r--r--docs/tutorial/quickstart.md32
5 files changed, 155 insertions, 54 deletions
diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md
index a3c19858..dea43cc0 100644
--- a/docs/tutorial/1-serialization.md
+++ b/docs/tutorial/1-serialization.md
@@ -16,7 +16,6 @@ The tutorial is fairly in-depth, so you should probably get a cookie and a cup o
Before we do anything else we'll create a new virtual environment, using [virtualenv]. This will make sure our package configuration is kept nicely isolated from any other projects we're working on.
- :::bash
virtualenv env
source env/bin/activate
@@ -75,12 +74,8 @@ For the purposes of this tutorial we're going to start by creating a simple `Sni
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
- language = models.CharField(choices=LANGUAGE_CHOICES,
- default='python',
- max_length=100)
- style = models.CharField(choices=STYLE_CHOICES,
- default='friendly',
- max_length=100)
+ language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
+ style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)
class Meta:
ordering = ('created',)
@@ -101,30 +96,27 @@ The first thing we need to get started on our Web API is to provide a way of ser
class SnippetSerializer(serializers.Serializer):
pk = serializers.IntegerField(read_only=True)
- title = serializers.CharField(required=False,
- max_length=100)
+ title = serializers.CharField(required=False, allow_blank=True, max_length=100)
code = serializers.CharField(style={'type': 'textarea'})
linenos = serializers.BooleanField(required=False)
- language = serializers.ChoiceField(choices=LANGUAGE_CHOICES,
- default='python')
- style = serializers.ChoiceField(choices=STYLE_CHOICES,
- default='friendly')
+ language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
+ style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')
- def create(self, validated_attrs):
+ def create(self, validated_data):
"""
Create and return a new `Snippet` instance, given the validated data.
"""
- return Snippet.objects.create(**validated_attrs)
+ return Snippet.objects.create(**validated_data)
- def update(self, instance, validated_attrs):
+ def update(self, instance, validated_data):
"""
Update and return an existing `Snippet` instance, given the validated data.
"""
- instance.title = validated_attrs.get('title', instance.title)
- instance.code = validated_attrs.get('code', instance.code)
- instance.linenos = validated_attrs.get('linenos', instance.linenos)
- instance.language = validated_attrs.get('language', instance.language)
- instance.style = validated_attrs.get('style', instance.style)
+ instance.title = validated_data.get('title', instance.title)
+ instance.code = validated_data.get('code', instance.code)
+ instance.linenos = validated_data.get('linenos', instance.linenos)
+ instance.language = validated_data.get('language', instance.language)
+ instance.style = validated_data.get('style', instance.style)
instance.save()
return instance
@@ -181,7 +173,9 @@ Deserialization is similar. First we parse a stream into Python native datatype
serializer = SnippetSerializer(data=data)
serializer.is_valid()
# True
- serializer.object
+ serializer.validated_data
+ # OrderedDict([('title', ''), ('code', 'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])
+ serializer.save()
# <Snippet: Snippet object>
Notice how similar the API is to working with forms. The similarity should become even more apparent when we start writing views that use our serializer.
@@ -210,7 +204,7 @@ One nice property that serializers have is that you can inspect all the fields i
>>> from snippets.serializers import SnippetSerializer
>>> serializer = SnippetSerializer()
- >>> print repr(serializer) # In python 3 use `print(repr(serializer))`
+ >>> print(repr(serializer))
SnippetSerializer():
id = IntegerField(label='ID', read_only=True)
title = CharField(allow_blank=True, max_length=100, required=False)
@@ -301,7 +295,7 @@ We'll also need a view which corresponds to an individual snippet, and can be us
Finally we need to wire these views up. Create the `snippets/urls.py` file:
- from django.conf.urls import patterns, url
+ from django.conf.urls import url
from snippets import views
urlpatterns = [
@@ -332,17 +326,51 @@ Quit out of the shell...
In another terminal window, we can test the server.
-We can get a list of all of the snippets.
-
- curl http://127.0.0.1:8000/snippets/
-
- [{"id": 1, "title": "", "code": "foo = \"bar\"\n", "linenos": false, "language": "python", "style": "friendly"}, {"id": 2, "title": "", "code": "print \"hello, world\"\n", "linenos": false, "language": "python", "style": "friendly"}]
+We can test our API using using [curl][curl] or [httpie][httpie]. Httpie is a user friendly http client that's written in Python. Let's install that.
+
+You can install httpie using pip:
+
+ pip install httpie
+
+Finally, we can get a list of all of the snippets:
+
+ http http://127.0.0.1:8000/snippets/
+
+ HTTP/1.1 200 OK
+ ...
+ [
+ {
+ "id": 1,
+ "title": "",
+ "code": "foo = \"bar\"\n",
+ "linenos": false,
+ "language": "python",
+ "style": "friendly"
+ },
+ {
+ "id": 2,
+ "title": "",
+ "code": "print \"hello, world\"\n",
+ "linenos": false,
+ "language": "python",
+ "style": "friendly"
+ }
+ ]
-Or we can get a particular snippet by referencing its id.
+Or we can get a particular snippet by referencing its id:
- curl http://127.0.0.1:8000/snippets/2/
+ http http://127.0.0.1:8000/snippets/2/
- {"id": 2, "title": "", "code": "print \"hello, world\"\n", "linenos": false, "language": "python", "style": "friendly"}
+ HTTP/1.1 200 OK
+ ...
+ {
+ "id": 2,
+ "title": "",
+ "code": "print \"hello, world\"\n",
+ "linenos": false,
+ "language": "python",
+ "style": "friendly"
+ }
Similarly, you can have the same json displayed by visiting these URLs in a web browser.
@@ -359,3 +387,5 @@ We'll see how we can start to improve things in [part 2 of the tutorial][tut-2].
[sandbox]: http://restframework.herokuapp.com/
[virtualenv]: http://www.virtualenv.org/en/latest/index.html
[tut-2]: 2-requests-and-responses.md
+[httpie]: https://github.com/jakubroztocil/httpie#installation
+[curl]: http://curl.haxx.se
diff --git a/docs/tutorial/2-requests-and-responses.md b/docs/tutorial/2-requests-and-responses.md
index f377c712..49e96d03 100644
--- a/docs/tutorial/2-requests-and-responses.md
+++ b/docs/tutorial/2-requests-and-responses.md
@@ -127,31 +127,64 @@ Go ahead and test the API from the command line, as we did in [tutorial part 1][
We can get a list of all of the snippets, as before.
- curl http://127.0.0.1:8000/snippets/
-
- [{"id": 1, "title": "", "code": "foo = \"bar\"\n", "linenos": false, "language": "python", "style": "friendly"}, {"id": 2, "title": "", "code": "print \"hello, world\"\n", "linenos": false, "language": "python", "style": "friendly"}]
+ http http://127.0.0.1:8000/snippets/
+
+ HTTP/1.1 200 OK
+ ...
+ [
+ {
+ "id": 1,
+ "title": "",
+ "code": "foo = \"bar\"\n",
+ "linenos": false,
+ "language": "python",
+ "style": "friendly"
+ },
+ {
+ "id": 2,
+ "title": "",
+ "code": "print \"hello, world\"\n",
+ "linenos": false,
+ "language": "python",
+ "style": "friendly"
+ }
+ ]
We can control the format of the response that we get back, either by using the `Accept` header:
- curl http://127.0.0.1:8000/snippets/ -H 'Accept: application/json' # Request JSON
- curl http://127.0.0.1:8000/snippets/ -H 'Accept: text/html' # Request HTML
+ http http://127.0.0.1:8000/snippets/ Accept:application/json # Request JSON
+ http http://127.0.0.1:8000/snippets/ Accept:text/html # Request HTML
Or by appending a format suffix:
- curl http://127.0.0.1:8000/snippets/.json # JSON suffix
- curl http://127.0.0.1:8000/snippets/.api # Browsable API suffix
+ http http://127.0.0.1:8000/snippets/.json # JSON suffix
+ http http://127.0.0.1:8000/snippets/.api # Browsable API suffix
Similarly, we can control the format of the request that we send, using the `Content-Type` header.
# POST using form data
- curl -X POST http://127.0.0.1:8000/snippets/ -d "code=print 123"
+ http --form POST http://127.0.0.1:8000/snippets/ code="print 123"
- {"id": 3, "title": "", "code": "print 123", "linenos": false, "language": "python", "style": "friendly"}
+ {
+ "id": 3,
+ "title": "",
+ "code": "print 123",
+ "linenos": false,
+ "language": "python",
+ "style": "friendly"
+ }
# POST using JSON
- curl -X POST http://127.0.0.1:8000/snippets/ -d '{"code": "print 456"}' -H "Content-Type: application/json"
-
- {"id": 4, "title": "", "code": "print 456", "linenos": true, "language": "python", "style": "friendly"}
+ http --json POST http://127.0.0.1:8000/snippets/ code="print 456"
+
+ {
+ "id": 4,
+ "title": "",
+ "code": "print 456",
+ "linenos": true,
+ "language": "python",
+ "style": "friendly"
+ }
Now go and open the API in a web browser, by visiting [http://127.0.0.1:8000/snippets/][devserver].
diff --git a/docs/tutorial/4-authentication-and-permissions.md b/docs/tutorial/4-authentication-and-permissions.md
index 4e4edeea..a6d27bf7 100644
--- a/docs/tutorial/4-authentication-and-permissions.md
+++ b/docs/tutorial/4-authentication-and-permissions.md
@@ -43,7 +43,7 @@ And now we can add a `.save()` method to our model class:
When that's all done we'll need to update our database tables.
Normally we'd create a database migration in order to do that, but for the purposes of this tutorial, let's just delete the database and start again.
- rm tmp.db
+ rm -f tmp.db db.sqlite3
rm -r snippets/migrations
python manage.py makemigrations snippets
python manage.py migrate
@@ -59,7 +59,7 @@ Now that we've got some users to work with, we'd better add representations of t
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
- snippets = serializers.PrimaryKeyRelatedField(many=True)
+ snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())
class Meta:
model = User
@@ -198,15 +198,25 @@ If we're interacting with the API programmatically we need to explicitly provide
If we try to create a snippet without authenticating, we'll get an error:
- curl -i -X POST http://127.0.0.1:8000/snippets/ -d "code=print 123"
+ http POST http://127.0.0.1:8000/snippets/ code="print 123"
- {"detail": "Authentication credentials were not provided."}
+ {
+ "detail": "Authentication credentials were not provided."
+ }
We can make a successful request by including the username and password of one of the users we created earlier.
- curl -X POST http://127.0.0.1:8000/snippets/ -d "code=print 789" -u tom:password
-
- {"id": 5, "owner": "tom", "title": "foo", "code": "print 789", "linenos": false, "language": "python", "style": "friendly"}
+ http POST -a tom:password http://127.0.0.1:8000/snippets/ code="print 789"
+
+ {
+ "id": 5,
+ "owner": "tom",
+ "title": "foo",
+ "code": "print 789",
+ "linenos": false,
+ "language": "python",
+ "style": "friendly"
+ }
## Summary
diff --git a/docs/tutorial/5-relationships-and-hyperlinked-apis.md b/docs/tutorial/5-relationships-and-hyperlinked-apis.md
index 50552616..58422929 100644
--- a/docs/tutorial/5-relationships-and-hyperlinked-apis.md
+++ b/docs/tutorial/5-relationships-and-hyperlinked-apis.md
@@ -44,7 +44,7 @@ Instead of using a concrete generic view, we'll use the base class for represent
As usual we need to add the new views that we've created in to our URLconf.
We'll add a url pattern for our new API root in `snippets/urls.py`:
- url(r'^$', 'api_root'),
+ url(r'^$', views.api_root),
And then add a url pattern for the snippet highlights:
diff --git a/docs/tutorial/quickstart.md b/docs/tutorial/quickstart.md
index 3e1ce0a9..c3f95994 100644
--- a/docs/tutorial/quickstart.md
+++ b/docs/tutorial/quickstart.md
@@ -19,10 +19,10 @@ Create a new Django project named `tutorial`, then start a new app called `quick
pip install djangorestframework
# Set up a new project with a single application
- django-admin.py startproject tutorial
+ django-admin.py startproject tutorial .
cd tutorial
django-admin.py startapp quickstart
- cd ..
+ cd ..
Now sync your database for the first time:
@@ -159,6 +159,33 @@ We can now access our API, both from the command-line, using tools like `curl`..
]
}
+Or using the [httpie][httpie], command line tool...
+
+ bash: http -a username:password http://127.0.0.1:8000/users/
+
+ HTTP/1.1 200 OK
+ ...
+ {
+ "count": 2,
+ "next": null,
+ "previous": null,
+ "results": [
+ {
+ "email": "admin@example.com",
+ "groups": [],
+ "url": "http://localhost:8000/users/1/",
+ "username": "paul"
+ },
+ {
+ "email": "tom@example.com",
+ "groups": [ ],
+ "url": "http://127.0.0.1:8000/users/2/",
+ "username": "tom"
+ }
+ ]
+ }
+
+
Or directly through the browser...
![Quick start image][image]
@@ -173,3 +200,4 @@ If you want to get a more in depth understanding of how REST framework fits toge
[image]: ../img/quickstart.png
[tutorial]: 1-serialization.md
[guide]: ../#api-guide
+[httpie]: https://github.com/jakubroztocil/httpie#installation