From af3fd098459fb559788735cb6b49a7108e11b18e Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 19 Jan 2013 15:31:21 +0000 Subject: Tweak imports in tutorial. Fixes #597. --- docs/tutorial/1-serialization.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md index d3ada9e3..f5ff167f 100644 --- a/docs/tutorial/1-serialization.md +++ b/docs/tutorial/1-serialization.md @@ -109,7 +109,7 @@ The first thing we need to get started on our Web API is provide a way of serial from django.forms import widgets from rest_framework import serializers - from snippets import models + from snippets.models import Snippet class SnippetSerializer(serializers.Serializer): @@ -138,7 +138,7 @@ The first thing we need to get started on our Web API is provide a way of serial return instance # Create new instance - return models.Snippet(**attrs) + return Snippet(**attrs) The first part of serializer class defines the fields that get serialized/deserialized. The `restore_object` method defines how fully fledged instances get created when deserializing data. -- cgit v1.2.3 From 2c76212e5454efa4d4d02c7051055c7957497d52 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sun, 20 Jan 2013 16:38:32 +0000 Subject: Add missing import to tutorial. Fixes #599 --- docs/tutorial/4-authentication-and-permissions.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/4-authentication-and-permissions.md b/docs/tutorial/4-authentication-and-permissions.md index f6daebb7..35aca8c6 100644 --- a/docs/tutorial/4-authentication-and-permissions.md +++ b/docs/tutorial/4-authentication-and-permissions.md @@ -54,6 +54,8 @@ You might also want to create a few different users, to use for testing the API. Now that we've got some users to work with, we'd better add representations of those users to our API. Creating a new serializer is easy: + from django.contrib.auth.models import User + class UserSerializer(serializers.ModelSerializer): snippets = serializers.ManyPrimaryKeyRelatedField() @@ -188,4 +190,4 @@ We've now got a fairly fine-grained set of permissions on our Web API, and end p In [part 5][tut-5] of the tutorial we'll look at how we can tie everything together by creating an HTML endpoint for our hightlighted snippets, and improve the cohesion of our API by using hyperlinking for the relationships within the system. -[tut-5]: 5-relationships-and-hyperlinked-apis.md \ No newline at end of file +[tut-5]: 5-relationships-and-hyperlinked-apis.md -- cgit v1.2.3 From a57c0c5aaecfbeaf900e6740fa60630f073d717b Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 23 Jan 2013 19:03:50 +0000 Subject: Docs tweak based on user feedback. --- docs/tutorial/4-authentication-and-permissions.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/4-authentication-and-permissions.md b/docs/tutorial/4-authentication-and-permissions.md index 35aca8c6..f5b4ce55 100644 --- a/docs/tutorial/4-authentication-and-permissions.md +++ b/docs/tutorial/4-authentication-and-permissions.md @@ -166,7 +166,8 @@ In the snippets app, create a new file, `permissions.py` if obj is None: return True - # Read permissions are allowed to any request + # Read permissions are allowed to any request, + # so we'll always allow GET, HEAD or OPTIONS requests. if request.method in permissions.SAFE_METHODS: return True -- cgit v1.2.3 From 4b0d4288c16f00e2f674e9c5120f3da57ec175ae Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 24 Jan 2013 13:01:28 +0000 Subject: Tweak linking style. --- docs/tutorial/5-relationships-and-hyperlinked-apis.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/5-relationships-and-hyperlinked-apis.md b/docs/tutorial/5-relationships-and-hyperlinked-apis.md index 27898f7b..de856611 100644 --- a/docs/tutorial/5-relationships-and-hyperlinked-apis.md +++ b/docs/tutorial/5-relationships-and-hyperlinked-apis.md @@ -165,7 +165,7 @@ We've reached the end of our tutorial. If you want to get more involved in the * Contribute on [GitHub][github] by reviewing and submitting issues, and making pull requests. * Join the [REST framework discussion group][group], and help build the community. -* [Follow the author on Twitter][twitter] and say hi. +* Follow [the author][twitter] on Twitter and say hi. **Now go build awesome things.** -- cgit v1.2.3 From 25f2d3b561bee946209bf0efeb6dc263af5e3be8 Mon Sep 17 00:00:00 2001 From: Guglielmo Date: Fri, 25 Jan 2013 18:16:14 +0100 Subject: Update docs/tutorial/4-authentication-and-permissions.md HTMLFormatter is in pygments.formatters.html--- docs/tutorial/4-authentication-and-permissions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/4-authentication-and-permissions.md b/docs/tutorial/4-authentication-and-permissions.md index f5b4ce55..e9e5246a 100644 --- a/docs/tutorial/4-authentication-and-permissions.md +++ b/docs/tutorial/4-authentication-and-permissions.md @@ -22,7 +22,7 @@ We'd also need to make sure that when the model is saved, that we populate the h We'll need some extra imports: from pygments.lexers import get_lexer_by_name - from pygments.formatters import HtmlFormatter + from pygments.formatters.html import HtmlFormatter from pygments import highlight And now we can add a `.save()` method to our model class: -- cgit v1.2.3 From c1dc1860da86dc119f2e80837c6b327af12b9b38 Mon Sep 17 00:00:00 2001 From: Mike TUMS Date: Mon, 28 Jan 2013 00:32:32 +0400 Subject: Update docs/tutorial/1-serialization.md Update for tutorials (manual serialization) to support HTTP PATCH method (partial update of instance)--- docs/tutorial/1-serialization.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md index f5ff167f..d66d2b97 100644 --- a/docs/tutorial/1-serialization.md +++ b/docs/tutorial/1-serialization.md @@ -129,12 +129,12 @@ The first thing we need to get started on our Web API is provide a way of serial Create or update a new snippet instance. """ if instance: - # Update existing instance - instance.title = attrs['title'] - instance.code = attrs['code'] - instance.linenos = attrs['linenos'] - instance.language = attrs['language'] - instance.style = attrs['style'] + # Update existing instance or part of it + instance.title = attrs.get('title', instance.title) + instance.code = attrs.get('code', instance.code) + instance.linenos = attrs.get('linenos', instance.linenos) + instance.language = attrs.get('language', instance.language) + instance.style = attrs.get('style', instance.style) return instance # Create new instance -- cgit v1.2.3 From b11628f429a241120c37981a17bbc375c23bb7ee Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 28 Jan 2013 07:52:04 +0000 Subject: Revert comment. --- docs/tutorial/1-serialization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md index d66d2b97..03c7ad71 100644 --- a/docs/tutorial/1-serialization.md +++ b/docs/tutorial/1-serialization.md @@ -129,7 +129,7 @@ The first thing we need to get started on our Web API is provide a way of serial Create or update a new snippet instance. """ if instance: - # Update existing instance or part of it + # Update existing instance instance.title = attrs.get('title', instance.title) instance.code = attrs.get('code', instance.code) instance.linenos = attrs.get('linenos', instance.linenos) -- cgit v1.2.3 From b1ae82b498b51f898ef6c767a5280c5db57c8afc Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 28 Jan 2013 07:52:22 +0000 Subject: And link to quickstart. --- docs/tutorial/1-serialization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md index 03c7ad71..5f292211 100644 --- a/docs/tutorial/1-serialization.md +++ b/docs/tutorial/1-serialization.md @@ -4,7 +4,7 @@ This tutorial will cover creating a simple pastebin code highlighting Web API. Along the way it will introduce the various components that make up REST framework, and give you a comprehensive understanding of how everything fits together. -The tutorial is fairly in-depth, so you should probably get a cookie and a cup of your favorite brew before getting started. +The tutorial is fairly in-depth, so you should probably get a cookie and a cup of your favorite brew before getting started. If you just want a quick overview, you should head over to the [quickstart] documentation instead. --- -- cgit v1.2.3 From 09b01887f234be55c14943028330f569823b2369 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 11 Feb 2013 12:47:56 +0000 Subject: New style object-level permission checks --- docs/tutorial/4-authentication-and-permissions.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/4-authentication-and-permissions.md b/docs/tutorial/4-authentication-and-permissions.md index e9e5246a..979421ea 100644 --- a/docs/tutorial/4-authentication-and-permissions.md +++ b/docs/tutorial/4-authentication-and-permissions.md @@ -161,11 +161,7 @@ In the snippets app, create a new file, `permissions.py` Custom permission to only allow owners of an object to edit it. """ - def has_permission(self, request, view, obj=None): - # Skip the check unless this is an object-level test - if obj is None: - return True - + def has_object_permission(self, request, view, obj): # Read permissions are allowed to any request, # so we'll always allow GET, HEAD or OPTIONS requests. if request.method in permissions.SAFE_METHODS: -- cgit v1.2.3 From 55fdac4176ac6629481a8cca8dd2463da9c594a2 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 12 Feb 2013 08:57:23 +0000 Subject: Use `many=True` for serializers. --- docs/tutorial/1-serialization.md | 29 ++++++++++++++-------- docs/tutorial/2-requests-and-responses.md | 2 +- docs/tutorial/3-class-based-views.md | 2 +- docs/tutorial/4-authentication-and-permissions.md | 2 +- .../5-relationships-and-hyperlinked-apis.md | 6 ++--- 5 files changed, 25 insertions(+), 16 deletions(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md index 5f292211..af5e8313 100644 --- a/docs/tutorial/1-serialization.md +++ b/docs/tutorial/1-serialization.md @@ -8,7 +8,7 @@ The tutorial is fairly in-depth, so you should probably get a cookie and a cup o --- -**Note**: The code for this tutorial is available in the [tomchristie/rest-framework-tutorial][repo] repository on GitHub. As pieces of code are introduced, they are committed to this repository. The completed implementation is also online as a sandbox version for testing, [available here][sandbox]. +**Note**: The code for this tutorial is available in the [tomchristie/rest-framework-tutorial][repo] repository on GitHub. The completed implementation is also online as a sandbox version for testing, [available here][sandbox]. --- @@ -150,13 +150,16 @@ Before we go any further we'll familiarize ourselves with using our new Serializ python manage.py shell -Okay, once we've got a few imports out of the way, let's create a code snippet to work with. +Okay, once we've got a few imports out of the way, let's create a couple of code snippets to work with. from snippets.models import Snippet from snippets.serializers import SnippetSerializer from rest_framework.renderers import JSONRenderer from rest_framework.parsers import JSONParser + snippet = Snippet(code='foo = "bar"\n') + snippet.save() + snippet = Snippet(code='print "hello, world"\n') snippet.save() @@ -164,13 +167,13 @@ We've now got a few snippet instances to play with. Let's take a look at serial serializer = SnippetSerializer(snippet) serializer.data - # {'pk': 1, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'} + # {'pk': 2, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'} At this point we've translated the model instance into python native datatypes. To finalize the serialization process we render the data into `json`. content = JSONRenderer().render(serializer.data) content - # '{"pk": 1, "title": "", "code": "print \\"hello, world\\"\\n", "linenos": false, "language": "python", "style": "friendly"}' + # '{"pk": 2, "title": "", "code": "print \\"hello, world\\"\\n", "linenos": false, "language": "python", "style": "friendly"}' Deserialization is similar. First we parse a stream into python native datatypes... @@ -189,6 +192,12 @@ Deserialization is similar. First we parse a stream into python native datatype 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. +We can also serialize querysets instead of model instances. To do so we simply add a `many=True` flag to the serializer arguments. + + serializer = SnippetSerializer(Snippet.objects.all(), many=True) + serializer.data + # [{'pk': 1, 'title': u'', 'code': u'foo = "bar"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}, {'pk': 2, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}] + ## Using ModelSerializers Our `SnippetSerializer` class is replicating a lot of information that's also contained in the `Snippet` model. It would be nice if we could keep out code a bit more concise. @@ -237,7 +246,7 @@ The root of our API is going to be a view that supports listing all the existing """ if request.method == 'GET': snippets = Snippet.objects.all() - serializer = SnippetSerializer(snippets) + serializer = SnippetSerializer(snippets, many=True) return JSONResponse(serializer.data) elif request.method == 'POST': @@ -312,19 +321,19 @@ and start up Django's development server In another terminal window, we can test the server. -We can get a list of all of the snippets (we only have one at the moment) +We can get a list of all of the snippets. curl http://127.0.0.1:8000/snippets/ - [{"id": 1, "title": "", "code": "print \"hello, world\"\n", "linenos": false, "language": "python", "style": "friendly"}] + [{"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 - curl http://127.0.0.1:8000/snippets/1/ + curl http://127.0.0.1:8000/snippets/2/ - {"id": 1, "title": "", "code": "print \"hello, world\"\n", "linenos": false, "language": "python", "style": "friendly"} + {"id": 2, "title": "", "code": "print \"hello, world\"\n", "linenos": false, "language": "python", "style": "friendly"} -Similarly, you can have the same json displayed by referencing these URLs from your favorite web browser. +Similarly, you can have the same json displayed by visiting these URLs in a web browser. ## Where are we now diff --git a/docs/tutorial/2-requests-and-responses.md b/docs/tutorial/2-requests-and-responses.md index 340ea28e..566c0dc6 100644 --- a/docs/tutorial/2-requests-and-responses.md +++ b/docs/tutorial/2-requests-and-responses.md @@ -51,7 +51,7 @@ We don't need our `JSONResponse` class anymore, so go ahead and delete that. On """ if request.method == 'GET': snippets = Snippet.objects.all() - serializer = SnippetSerializer(snippets) + serializer = SnippetSerializer(snippets, many=True) return Response(serializer.data) elif request.method == 'POST': diff --git a/docs/tutorial/3-class-based-views.md b/docs/tutorial/3-class-based-views.md index 290ea5e9..e05017c5 100644 --- a/docs/tutorial/3-class-based-views.md +++ b/docs/tutorial/3-class-based-views.md @@ -20,7 +20,7 @@ We'll start by rewriting the root view as a class based view. All this involves """ def get(self, request, format=None): snippets = Snippet.objects.all() - serializer = SnippetSerializer(snippets) + serializer = SnippetSerializer(snippets, many=True) return Response(serializer.data) def post(self, request, format=None): diff --git a/docs/tutorial/4-authentication-and-permissions.md b/docs/tutorial/4-authentication-and-permissions.md index 979421ea..282386c7 100644 --- a/docs/tutorial/4-authentication-and-permissions.md +++ b/docs/tutorial/4-authentication-and-permissions.md @@ -57,7 +57,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.ManyPrimaryKeyRelatedField() + snippets = serializers.PrimaryKeyRelatedField(many=True) class Meta: model = User diff --git a/docs/tutorial/5-relationships-and-hyperlinked-apis.md b/docs/tutorial/5-relationships-and-hyperlinked-apis.md index de856611..81be333b 100644 --- a/docs/tutorial/5-relationships-and-hyperlinked-apis.md +++ b/docs/tutorial/5-relationships-and-hyperlinked-apis.md @@ -70,8 +70,8 @@ The `HyperlinkedModelSerializer` has the following differences from `ModelSerial * It does not include the `pk` field by default. * It includes a `url` field, using `HyperlinkedIdentityField`. -* Relationships use `HyperlinkedRelatedField` and `ManyHyperlinkedRelatedField`, - instead of `PrimaryKeyRelatedField` and `ManyPrimaryKeyRelatedField`. +* Relationships use `HyperlinkedRelatedField`, + instead of `PrimaryKeyRelatedField`. We can easily re-write our existing serializers to use hyperlinking. @@ -86,7 +86,7 @@ We can easily re-write our existing serializers to use hyperlinking. class UserSerializer(serializers.HyperlinkedModelSerializer): - snippets = serializers.ManyHyperlinkedRelatedField(view_name='snippet-detail') + snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail') class Meta: model = User -- cgit v1.2.3 From 34145408cb73213c2f6c1e9ab53795e6d7e3a3f6 Mon Sep 17 00:00:00 2001 From: eofs Date: Thu, 14 Feb 2013 13:21:54 +0200 Subject: Missing imports added --- docs/tutorial/1-serialization.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md index af5e8313..53d24136 100644 --- a/docs/tutorial/1-serialization.md +++ b/docs/tutorial/1-serialization.md @@ -109,7 +109,7 @@ The first thing we need to get started on our Web API is provide a way of serial from django.forms import widgets from rest_framework import serializers - from snippets.models import Snippet + from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES class SnippetSerializer(serializers.Serializer): @@ -119,9 +119,9 @@ The first thing we need to get started on our Web API is provide a way of serial code = serializers.CharField(widget=widgets.Textarea, max_length=100000) linenos = serializers.BooleanField(required=False) - language = serializers.ChoiceField(choices=models.LANGUAGE_CHOICES, + language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python') - style = serializers.ChoiceField(choices=models.STYLE_CHOICES, + style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly') def restore_object(self, attrs, instance=None): -- cgit v1.2.3 From 41d3fe09cf3dd80cb8efed13dd886645ae7be470 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 23 Feb 2013 21:29:13 +0000 Subject: Add missing `blank=True` to model in tutorial. --- docs/tutorial/1-serialization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md index 53d24136..691b3500 100644 --- a/docs/tutorial/1-serialization.md +++ b/docs/tutorial/1-serialization.md @@ -86,7 +86,7 @@ For the purposes of this tutorial we're going to start by creating a simple `Sni class Snippet(models.Model): created = models.DateTimeField(auto_now_add=True) - title = models.CharField(max_length=100, default='') + title = models.CharField(max_length=100, blank=True, default='') code = models.TextField() linenos = models.BooleanField(default=False) language = models.CharField(choices=LANGUAGE_CHOICES, -- cgit v1.2.3 From 5b03de8287b04177c30815f5c798fe5c69e0d122 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 23 Feb 2013 21:29:52 +0000 Subject: Add curl examples. --- docs/tutorial/2-requests-and-responses.md | 36 +++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/2-requests-and-responses.md b/docs/tutorial/2-requests-and-responses.md index 566c0dc6..63cee3a6 100644 --- a/docs/tutorial/2-requests-and-responses.md +++ b/docs/tutorial/2-requests-and-responses.md @@ -75,11 +75,11 @@ Here is the view for an individual snippet. snippet = Snippet.objects.get(pk=pk) except Snippet.DoesNotExist: return Response(status=status.HTTP_404_NOT_FOUND) - + if request.method == 'GET': serializer = SnippetSerializer(snippet) return Response(serializer.data) - + elif request.method == 'PUT': serializer = SnippetSerializer(snippet, data=request.DATA) if serializer.is_valid(): @@ -126,13 +126,41 @@ We don't necessarily need to add these extra url patterns in, but it gives us a Go ahead and test the API from the command line, as we did in [tutorial part 1][tut-1]. Everything is working pretty similarly, although we've got some nicer error handling if we send invalid requests. -**TODO: Describe using accept headers, content-type headers, and format suffixed URLs** +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"}] + +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 + +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 # Browseable 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" + + {"id": 3, "title": "", "code": "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"} Now go and open the API in a web browser, by visiting [http://127.0.0.1:8000/snippets/][devserver]. ### Browsability -Because the API chooses a return format based on what the client asks for, it will, by default, return an HTML-formatted representation of the resource when that resource is requested by a browser. This allows for the API to be easily browsable and usable by humans. +Because the API chooses the content type of the response based on the client request, it will, by default, return an HTML-formatted representation of the resource when that resource is requested by a web browser. This allows for the API to return a fully web-browsable HTML representation. + +Having a web-browseable API is a huge usability win, and makes developing and using your API much easier. It also dramatically lowers the barrier-to-entry for other developers wanting to inspect and work with your API. See the [browsable api][browseable-api] topic for more information about the browsable API feature and how to customize it. -- cgit v1.2.3 From 9e2131715a40110a5130a1f391de7989b2ed23a9 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 23 Feb 2013 21:52:26 +0000 Subject: Formatting. --- docs/tutorial/1-serialization.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md index 691b3500..6709f751 100644 --- a/docs/tutorial/1-serialization.md +++ b/docs/tutorial/1-serialization.md @@ -304,11 +304,11 @@ It's worth noting that there are a couple of edge cases we're not dealing with p Now we can start up a sample server that serves our snippets. -Quit out of the shell +Quit out of the shell... quit() -and start up Django's development server +...and start up Django's development server. python manage.py runserver @@ -327,7 +327,7 @@ We can get a list of all of the 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"}] -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/ -- cgit v1.2.3 From 4a80dff1efee238ef789a2f90ba150d05566d3e2 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 23 Feb 2013 21:52:46 +0000 Subject: Autenticating with curl example. --- docs/tutorial/4-authentication-and-permissions.md | 25 +++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/4-authentication-and-permissions.md b/docs/tutorial/4-authentication-and-permissions.md index 282386c7..f295aeb6 100644 --- a/docs/tutorial/4-authentication-and-permissions.md +++ b/docs/tutorial/4-authentication-and-permissions.md @@ -104,8 +104,6 @@ This field is doing something quite interesting. The `source` argument controls The field we've added is the untyped `Field` class, in contrast to the other typed fields, such as `CharField`, `BooleanField` etc... The untyped `Field` is always read-only, and will be used for serialized representations, but will not be used for updating model instances when they are deserialized. -**TODO: Explain the SessionAuthentication and BasicAuthentication classes, and demonstrate using HTTP basic authentication with curl requests** - ## Adding required permissions to views Now that code snippets are associated with users, we want to make sure that only authenticated users are able to create, update and delete code snippets. @@ -120,8 +118,6 @@ Then, add the following property to **both** the `SnippetList` and `SnippetDetai permission_classes = (permissions.IsAuthenticatedOrReadOnly,) -**TODO: Now that the permissions are restricted, demonstrate using HTTP basic authentication with curl requests** - ## Adding login to the Browseable API If you open a browser and navigate to the browseable API at the moment, you'll find that you're no longer able to create new code snippets. In order to do so we'd need to be able to login as a user. @@ -181,10 +177,31 @@ Make sure to also import the `IsOwnerOrReadOnly` class. Now, if you open a browser again, you find that the 'DELETE' and 'PUT' actions only appear on a snippet instance endpoint if you're logged in as the same user that created the code snippet. +## Authenticating with the API + +Because we now have a set of permissions on the API, we need to authenticate our requests to it if we want to edit any snippets. We havn't set up any [authentication classes][authentication], so the defaults are currently applied, which are `SessionAuthentication` and `BasicAuthentication`. + +When we interact with the API through the web browser, we can login, and the browser session will then provide the required authentication for the requests. + +If we're interacting with the API programmatically we need to explicitly provide the authentication credentials on each request. + +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" + + {"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 + + {"url": "http://127.0.0.1:8000/snippets/5/", "highlight": "http://127.0.0.1:8000/snippets/5/highlight/", "owner": "tom", "title": "foo", "code": "print 789", "linenos": false, "language": "python", "style": "friendly"} + ## Summary We've now got a fairly fine-grained set of permissions on our Web API, and end points for users of the system and for the code snippets that they have created. In [part 5][tut-5] of the tutorial we'll look at how we can tie everything together by creating an HTML endpoint for our hightlighted snippets, and improve the cohesion of our API by using hyperlinking for the relationships within the system. +[authentication]: ../api-guide/authentication.md [tut-5]: 5-relationships-and-hyperlinked-apis.md -- cgit v1.2.3 From ea7d73f57e4cb69d5321188e33019c7ab3b89d8e Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 23 Feb 2013 22:07:33 +0000 Subject: Spelling. --- docs/tutorial/4-authentication-and-permissions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/4-authentication-and-permissions.md b/docs/tutorial/4-authentication-and-permissions.md index f295aeb6..9ac9deac 100644 --- a/docs/tutorial/4-authentication-and-permissions.md +++ b/docs/tutorial/4-authentication-and-permissions.md @@ -201,7 +201,7 @@ We can make a successful request by including the username and password of one o We've now got a fairly fine-grained set of permissions on our Web API, and end points for users of the system and for the code snippets that they have created. -In [part 5][tut-5] of the tutorial we'll look at how we can tie everything together by creating an HTML endpoint for our hightlighted snippets, and improve the cohesion of our API by using hyperlinking for the relationships within the system. +In [part 5][tut-5] of the tutorial we'll look at how we can tie everything together by creating an HTML endpoint for our highlighted snippets, and improve the cohesion of our API by using hyperlinking for the relationships within the system. [authentication]: ../api-guide/authentication.md [tut-5]: 5-relationships-and-hyperlinked-apis.md -- cgit v1.2.3 From 4599cd97cbbfd2f569408cbadef3a3753d19f406 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sat, 23 Feb 2013 22:13:06 +0000 Subject: Fix curl response. Didn't map to the correct stage of the tutorial. --- docs/tutorial/4-authentication-and-permissions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/4-authentication-and-permissions.md b/docs/tutorial/4-authentication-and-permissions.md index 9ac9deac..3c4e042b 100644 --- a/docs/tutorial/4-authentication-and-permissions.md +++ b/docs/tutorial/4-authentication-and-permissions.md @@ -195,7 +195,7 @@ We can make a successful request by including the username and password of one o curl -X POST http://127.0.0.1:8000/snippets/ -d "code=print 789" -u tom:password - {"url": "http://127.0.0.1:8000/snippets/5/", "highlight": "http://127.0.0.1:8000/snippets/5/highlight/", "owner": "tom", "title": "foo", "code": "print 789", "linenos": false, "language": "python", "style": "friendly"} + {"id": 5, "owner": "tom", "title": "foo", "code": "print 789", "linenos": false, "language": "python", "style": "friendly"} ## Summary -- cgit v1.2.3 From 70db39859586aa49b6065ee1625fbfba3b50ae23 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Mon, 25 Feb 2013 21:31:12 +0100 Subject: Renamed UserInstance to UserDetail in docs --- docs/tutorial/4-authentication-and-permissions.md | 4 ++-- docs/tutorial/5-relationships-and-hyperlinked-apis.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/4-authentication-and-permissions.md b/docs/tutorial/4-authentication-and-permissions.md index 3c4e042b..3ee755a2 100644 --- a/docs/tutorial/4-authentication-and-permissions.md +++ b/docs/tutorial/4-authentication-and-permissions.md @@ -72,14 +72,14 @@ We'll also add a couple of views. We'd like to just use read-only views for the serializer_class = UserSerializer - class UserInstance(generics.RetrieveAPIView): + class UserDetail(generics.RetrieveAPIView): model = User serializer_class = UserSerializer Finally we need to add those views into the API, by referencing them from the URL conf. url(r'^users/$', views.UserList.as_view()), - url(r'^users/(?P[0-9]+)/$', views.UserInstance.as_view()), + url(r'^users/(?P[0-9]+)/$', views.UserDetail.as_view()), ## Associating Snippets with Users diff --git a/docs/tutorial/5-relationships-and-hyperlinked-apis.md b/docs/tutorial/5-relationships-and-hyperlinked-apis.md index 81be333b..a702a09d 100644 --- a/docs/tutorial/5-relationships-and-hyperlinked-apis.md +++ b/docs/tutorial/5-relationships-and-hyperlinked-apis.md @@ -123,7 +123,7 @@ After adding all those names into our URLconf, our final `'urls.py'` file should views.UserList.as_view(), name='user-list'), url(r'^users/(?P[0-9]+)/$', - views.UserInstance.as_view(), + views.UserDetail.as_view(), name='user-detail') )) @@ -173,4 +173,4 @@ We've reached the end of our tutorial. If you want to get more involved in the [sandbox]: http://restframework.herokuapp.com/ [github]: https://github.com/tomchristie/django-rest-framework [group]: https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework -[twitter]: https://twitter.com/_tomchristie \ No newline at end of file +[twitter]: https://twitter.com/_tomchristie -- cgit v1.2.3 From ef0caf64d326bacdf367e002e5537b8c0d444d34 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sun, 17 Mar 2013 19:59:13 +0000 Subject: Extra note on method --- docs/tutorial/1-serialization.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md index 6709f751..205ee7e0 100644 --- a/docs/tutorial/1-serialization.md +++ b/docs/tutorial/1-serialization.md @@ -126,7 +126,11 @@ The first thing we need to get started on our Web API is provide a way of serial def restore_object(self, attrs, instance=None): """ - Create or update a new snippet instance. + Create or update a new snippet instance, given a dictionary + of deserialized field values. + + Note that if we don't define this method, then deserializing + data will simply return a dictionary of items. """ if instance: # Update existing instance -- cgit v1.2.3