aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorTom Christie2013-01-07 21:04:52 +0000
committerTom Christie2013-01-07 21:04:52 +0000
commit36fa722ebb1b438b710b90fe470fbdbf82fd676e (patch)
tree9a837478ff46ebeed0b03fe9a430d72695cc2784 /docs
parent873a142af2f63084fd10bf35c13e79131837da07 (diff)
parente429f702e00ed807d68e90cd6a6af2749eb0b73e (diff)
downloaddjango-rest-framework-36fa722ebb1b438b710b90fe470fbdbf82fd676e.tar.bz2
Merged to latest master
Diffstat (limited to 'docs')
-rw-r--r--docs/api-guide/authentication.md31
-rw-r--r--docs/api-guide/fields.md180
-rw-r--r--docs/api-guide/filtering.md7
-rw-r--r--docs/api-guide/generic-views.md60
-rw-r--r--docs/api-guide/pagination.md33
-rw-r--r--docs/api-guide/parsers.md13
-rw-r--r--docs/api-guide/permissions.md2
-rw-r--r--docs/api-guide/relations.md139
-rw-r--r--docs/api-guide/renderers.md14
-rw-r--r--docs/api-guide/serializers.md35
-rw-r--r--docs/api-guide/settings.md22
-rw-r--r--docs/api-guide/views.md4
-rw-r--r--docs/index.md23
-rw-r--r--docs/template.html1
-rw-r--r--docs/topics/credits.md72
-rw-r--r--docs/topics/release-notes.md206
-rw-r--r--docs/topics/rest-hypermedia-hateoas.md3
-rw-r--r--docs/tutorial/1-serialization.md15
-rw-r--r--docs/tutorial/2-requests-and-responses.md12
-rw-r--r--docs/tutorial/3-class-based-views.md22
-rw-r--r--docs/tutorial/4-authentication-and-permissions.md8
-rw-r--r--docs/tutorial/5-relationships-and-hyperlinked-apis.md8
-rw-r--r--docs/tutorial/quickstart.md4
23 files changed, 683 insertions, 231 deletions
diff --git a/docs/api-guide/authentication.md b/docs/api-guide/authentication.md
index b2323d62..4dfcb0f1 100644
--- a/docs/api-guide/authentication.md
+++ b/docs/api-guide/authentication.md
@@ -126,19 +126,36 @@ Unauthenticated responses that are denied permission will result in an `HTTP 401
**Note:** If you use `TokenAuthentication` in production you must ensure that your API is only available over `https` only.
+<<<<<<< HEAD
<!--## OAuth2Authentication
+=======
+If you want every user to have an automatically generated Token, you can simply catch the User's `post_save` signal.
-This authentication scheme uses the [OAuth 2.0][oauth] protocol to authenticate requests. OAuth is appropriate for server-server setups, such as when you want to allow a third-party service to access your API on a user's behalf.
+ @receiver(post_save, sender=User)
+ def create_auth_token(sender, instance=None, created=False, **kwargs):
+ if created:
+ Token.objects.create(user=instance)
-If successfully authenticated, `OAuth2Authentication` provides the following credentials.
+If you've already created some users, you can generate tokens for all existing users like this:
-* `request.user` will be a Django `User` instance.
-* `request.auth` will be a `rest_framework.models.OAuthToken` instance.
+ from django.contrib.auth.models import User
+ from rest_framework.authtoken.models import Token
+
+ for user in User.objects.all():
+ Token.objects.get_or_create(user=user)
+
+When using `TokenAuthentication`, you may want to provide a mechanism for clients to obtain a token given the username and password.
+REST framework provides a built-in view to provide this behavior. To use it, add the `obtain_auth_token` view to your URLconf:
+
+ urlpatterns += patterns('',
+ url(r'^api-token-auth/', 'rest_framework.authtoken.views.obtain_auth_token')
+ )
+
+Note that the URL part of the pattern can be whatever you want to use.
-**TODO**: Note type of response (401 vs 403)
+The `obtain_auth_token` view will return a JSON response when valid `username` and `password` fields are POSTed to the view using form data or JSON:
-**TODO**: Implement OAuth2Authentication, using django-oauth2-provider.
--->
+ { 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' }
## SessionAuthentication
diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md
index 0485b158..5bc8f7f7 100644
--- a/docs/api-guide/fields.md
+++ b/docs/api-guide/fields.md
@@ -2,11 +2,11 @@
# Serializer fields
-> Flat is better than nested.
+> Each field in a Form class is responsible not only for validating data, but also for "cleaning" it -- normalizing it to a consistent format.
>
-> &mdash; [The Zen of Python][cite]
+> &mdash; [Django documentation][cite]
-Serializer fields handle converting between primative values and internal datatypes. They also deal with validating input values, as well as retrieving and setting the values from their parent objects.
+Serializer fields handle converting between primitive values and internal datatypes. They also deal with validating input values, as well as retrieving and setting the values from their parent objects.
---
@@ -28,7 +28,7 @@ Defaults to the name of the field.
### `read_only`
-Set this to `True` to ensure that the field is used when serializing a representation, but is not used when updating an instance dureing deserialization.
+Set this to `True` to ensure that the field is used when serializing a representation, but is not used when updating an instance during deserialization.
Defaults to `False`
@@ -41,7 +41,7 @@ Defaults to `True`.
### `default`
-If set, this gives the default value that will be used for the field if none is supplied. If not set the default behaviour is to not populate the attribute at all.
+If set, this gives the default value that will be used for the field if none is supplied. If not set the default behavior is to not populate the attribute at all.
### `validators`
@@ -96,9 +96,9 @@ Would produce output similar to:
'expired': True
}
-By default, the `Field` class will perform a basic translation of the source value into primative datatypes, falling back to unicode representations of complex datatypes when necessary.
+By default, the `Field` class will perform a basic translation of the source value into primitive datatypes, falling back to unicode representations of complex datatypes when necessary.
-You can customize this behaviour by overriding the `.to_native(self, value)` method.
+You can customize this behavior by overriding the `.to_native(self, value)` method.
## WritableField
@@ -110,6 +110,24 @@ A generic field that can be tied to any arbitrary model field. The `ModelField`
**Signature:** `ModelField(model_field=<Django ModelField class>)`
+## SerializerMethodField
+
+This is a read-only field. It gets its value by calling a method on the serializer class it is attached to. It can be used to add any sort of data to the serialized representation of your object. The field's constructor accepts a single argument, which is the name of the method on the serializer to be called. The method should accept a single argument (in addition to `self`), which is the object being serialized. It should return whatever you want to be included in the serialized representation of the object. For example:
+
+ from rest_framework import serializers
+ from django.contrib.auth.models import User
+ from django.utils.timezone import now
+
+ class UserSerializer(serializers.ModelSerializer):
+
+ days_since_joined = serializers.SerializerMethodField('get_days_since_joined')
+
+ class Meta:
+ model = User
+
+ def get_days_since_joined(self, obj):
+ return (now() - obj.date_joined).days
+
---
# Typed Fields
@@ -131,6 +149,18 @@ or `django.db.models.fields.TextField`.
**Signature:** `CharField(max_length=None, min_length=None)`
+## URLField
+
+Corresponds to `django.db.models.fields.URLField`. Uses Django's `django.core.validators.URLValidator` for validation.
+
+**Signature:** `CharField(max_length=200, min_length=None)`
+
+## SlugField
+
+Corresponds to `django.db.models.fields.SlugField`.
+
+**Signature:** `CharField(max_length=50, min_length=None)`
+
## ChoiceField
A field that can accept a value out of a limited set of choices.
@@ -141,6 +171,16 @@ A text representation, validates the text to be a valid e-mail address.
Corresponds to `django.db.models.fields.EmailField`
+## RegexField
+
+A text representation, that validates the given value matches against a certain regular expression.
+
+Uses Django's `django.core.validators.RegexValidator` for validation.
+
+Corresponds to `django.forms.fields.RegexField`
+
+**Signature:** `RegexField(regex, max_length=None, min_length=None)`
+
## DateField
A date representation.
@@ -165,124 +205,32 @@ A floating point representation.
Corresponds to `django.db.models.fields.FloatField`.
----
-
-# Relational Fields
-
-Relational fields are used to represent model relationships. They can be applied to `ForeignKey`, `ManyToManyField` and `OneToOneField` relationships, as well as to reverse relationships, and custom relationships such as `GenericForeignKey`.
+## FileField
-## RelatedField
+A file representation. Performs Django's standard FileField validation.
-This field can be applied to any of the following:
+Corresponds to `django.forms.fields.FileField`.
-* A `ForeignKey` field.
-* A `OneToOneField` field.
-* A reverse OneToOne relationship
-* Any other "to-one" relationship.
+**Signature:** `FileField(max_length=None, allow_empty_file=False)`
-By default `RelatedField` will represent the target of the field using it's `__unicode__` method.
+ - `max_length` designates the maximum length for the file name.
+
+ - `allow_empty_file` designates if empty files are allowed.
-You can customise this behaviour by subclassing `ManyRelatedField`, and overriding the `.to_native(self, value)` method.
+## ImageField
-## ManyRelatedField
+An image representation.
-This field can be applied to any of the following:
-
-* A `ManyToManyField` field.
-* A reverse ManyToMany relationship.
-* A reverse ForeignKey relationship
-* Any other "to-many" relationship.
+Corresponds to `django.forms.fields.ImageField`.
-By default `ManyRelatedField` will represent the targets of the field using their `__unicode__` method.
+Requires the `PIL` package.
-For example, given the following models:
+Signature and validation is the same as with `FileField`.
- class TaggedItem(models.Model):
- """
- Tags arbitrary model instances using a generic relation.
-
- See: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/
- """
- tag = models.SlugField()
- content_type = models.ForeignKey(ContentType)
- object_id = models.PositiveIntegerField()
- content_object = GenericForeignKey('content_type', 'object_id')
-
- def __unicode__(self):
- return self.tag
-
-
- class Bookmark(models.Model):
- """
- A bookmark consists of a URL, and 0 or more descriptive tags.
- """
- url = models.URLField()
- tags = GenericRelation(TaggedItem)
-
-And a model serializer defined like this:
-
- class BookmarkSerializer(serializers.ModelSerializer):
- tags = serializers.ManyRelatedField(source='tags')
-
- class Meta:
- model = Bookmark
- exclude = ('id',)
-
-Then an example output format for a Bookmark instance would be:
-
- {
- 'tags': [u'django', u'python'],
- 'url': u'https://www.djangoproject.com/'
- }
-
-## PrimaryKeyRelatedField / ManyPrimaryKeyRelatedField
-
-`PrimaryKeyRelatedField` and `ManyPrimaryKeyRelatedField` will represent the target of the relationship using it's primary key.
-
-By default these fields are read-write, although you can change this behaviour using the `read_only` flag.
-
-**Arguments**:
-
-* `queryset` - By default `ModelSerializer` classes will use the default queryset for the relationship. `Serializer` classes must either set a queryset explicitly, or set `read_only=True`.
-
-## SlugRelatedField / ManySlugRelatedField
-
-`SlugRelatedField` and `ManySlugRelatedField` will represent the target of the relationship using a unique slug.
-
-By default these fields read-write, although you can change this behaviour using the `read_only` flag.
-
-**Arguments**:
-
-* `slug_field` - The field on the target that should be used to represent it. This should be a field that uniquely identifies any given instance. For example, `username`.
-* `queryset` - By default `ModelSerializer` classes will use the default queryset for the relationship. `Serializer` classes must either set a queryset explicitly, or set `read_only=True`.
-
-## HyperlinkedRelatedField / ManyHyperlinkedRelatedField
-
-`HyperlinkedRelatedField` and `ManyHyperlinkedRelatedField` will represent the target of the relationship using a hyperlink.
-
-By default, `HyperlinkedRelatedField` is read-write, although you can change this behaviour using the `read_only` flag.
-
-**Arguments**:
-
-* `view_name` - The view name that should be used as the target of the relationship. **required**.
-* `format` - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the `format` argument.
-* `queryset` - By default `ModelSerializer` classes will use the default queryset for the relationship. `Serializer` classes must either set a queryset explicitly, or set `read_only=True`.
-* `slug_field` - The field on the target that should be used for the lookup. Default is `'slug'`.
-* `pk_url_kwarg` - The named url parameter for the pk field lookup. Default is `pk`.
-* `slug_url_kwarg` - The named url parameter for the slug field lookup. Default is to use the same value as given for `slug_field`.
-
-## HyperLinkedIdentityField
-
-This field can be applied as an identity relationship, such as the `'url'` field on a HyperlinkedModelSerializer.
-
-This field is always read-only.
-
-**Arguments**:
+---
-* `view_name` - The view name that should be used as the target of the relationship. **required**.
-* `format` - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the `format` argument.
-* `slug_field` - The field on the target that should be used for the lookup. Default is `'slug'`.
-* `pk_url_kwarg` - The named url parameter for the pk field lookup. Default is `pk`.
-* `slug_url_kwarg` - The named url parameter for the slug field lookup. Default is to use the same value as given for `slug_field`.
+**Note:** `FileFields` and `ImageFields` are only suitable for use with MultiPartParser, since e.g. json doesn't support file uploads.
+Django's regular [FILE_UPLOAD_HANDLERS] are used for handling uploaded files.
-[cite]: http://www.python.org/dev/peps/pep-0020/
+[cite]: https://docs.djangoproject.com/en/dev/ref/forms/api/#django.forms.Form.cleaned_data
+[FILE_UPLOAD_HANDLERS]: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS
diff --git a/docs/api-guide/filtering.md b/docs/api-guide/filtering.md
index 14ab9a26..53ea7cbc 100644
--- a/docs/api-guide/filtering.md
+++ b/docs/api-guide/filtering.md
@@ -71,7 +71,7 @@ We can override `.get_queryset()` to deal with URLs such as `http://example.com/
by filtering against a `username` query parameter in the URL.
"""
queryset = Purchase.objects.all()
- username = self.request.QUERY_PARAMS.get('username', None):
+ username = self.request.QUERY_PARAMS.get('username', None)
if username is not None:
queryset = queryset.filter(purchaser__username=username)
return queryset
@@ -84,9 +84,9 @@ As well as being able to override the default queryset, REST framework also incl
REST framework supports pluggable backends to implement filtering, and provides an implementation which uses the [django-filter] package.
-To use REST framework's default filtering backend, first install `django-filter`.
+To use REST framework's filtering backend, first install `django-filter`.
- pip install -e git+https://github.com/alex/django-filter.git#egg=django-filter
+ pip install django-filter
You must also set the filter backend to `DjangoFilterBackend` in your settings:
@@ -94,7 +94,6 @@ You must also set the filter backend to `DjangoFilterBackend` in your settings:
'FILTER_BACKEND': 'rest_framework.filters.DjangoFilterBackend'
}
-**Note**: The currently supported version of `django-filter` is the `master` branch. A PyPI release is expected to be coming soon.
## Specifying filter fields
diff --git a/docs/api-guide/generic-views.md b/docs/api-guide/generic-views.md
index 360ef1a2..693e210d 100644
--- a/docs/api-guide/generic-views.md
+++ b/docs/api-guide/generic-views.md
@@ -7,11 +7,11 @@
>
> &mdash; [Django Documentation][cite]
-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.
+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.
The generic views provided by REST framework allow you to quickly build API views that map closely to your database models.
-If the generic views don't suit the needs of your API, you can drop down to using the regular `APIView` class, or reuse the mixins and base classes used by the generic views to compose your own set of reusable generic views.
+If the generic views don't suit the needs of your API, you can drop down to using the regular `APIView` class, or reuse the mixins and base classes used by the generic views to compose your own set of reusable generic views.
## Examples
@@ -29,7 +29,7 @@ For more complex cases you might also want to override various methods on the vi
model = User
serializer_class = UserSerializer
permission_classes = (IsAdminUser,)
-
+
def get_paginate_by(self, queryset):
"""
Use smaller pagination for HTML representations.
@@ -85,7 +85,7 @@ Extends: [SingleObjectAPIView], [DestroyModelMixin]
Used for **update-only** endpoints for a **single model instance**.
-Provides a `put` method handler.
+Provides `put` and `patch` method handlers.
Extends: [SingleObjectAPIView], [UpdateModelMixin]
@@ -97,6 +97,14 @@ Provides `get` and `post` method handlers.
Extends: [MultipleObjectAPIView], [ListModelMixin], [CreateModelMixin]
+## RetrieveUpdateAPIView
+
+Used for **read or update** endpoints to represent a **single model instance**.
+
+Provides `get`, `put` and `patch` method handlers.
+
+Extends: [SingleObjectAPIView], [RetrieveModelMixin], [UpdateModelMixin]
+
## RetrieveDestroyAPIView
Used for **read or delete** endpoints to represent a **single model instance**.
@@ -109,7 +117,7 @@ Extends: [SingleObjectAPIView], [RetrieveModelMixin], [DestroyModelMixin]
Used for **read-write-delete** endpoints to represent a **single model instance**.
-Provides `get`, `put` and `delete` method handlers.
+Provides `get`, `put`, `patch` and `delete` method handlers.
Extends: [SingleObjectAPIView], [RetrieveModelMixin], [UpdateModelMixin], [DestroyModelMixin]
@@ -123,52 +131,90 @@ Each of the generic views provided is built by combining one of the base views b
Extends REST framework's `APIView` class, adding support for serialization of model instances and model querysets.
+**Attributes**:
+
+* `model` - The model that should be used for this view. Used as a fallback for determining the serializer if `serializer_class` is not set, and as a fallback for determining the queryset if `queryset` is not set. Otherwise not required.
+* `serializer_class` - The serializer class that should be used for validating and deserializing input, and for serializing output. If unset, this defaults to creating a serializer class using `self.model`, with the `DEFAULT_MODEL_SERIALIZER_CLASS` setting as the base serializer class.
+
## MultipleObjectAPIView
Provides a base view for acting on a single object, by combining REST framework's `APIView`, and Django's [MultipleObjectMixin].
**See also:** ccbv.co.uk documentation for [MultipleObjectMixin][multiple-object-mixin-classy].
+**Attributes**:
+
+* `queryset` - The queryset that should be used for returning objects from this view. If unset, defaults to the default queryset manager for `self.model`.
+* `paginate_by` - The size of pages to use with paginated data. If set to `None` then pagination is turned off. If unset this uses the same value as the `PAGINATE_BY` setting, which defaults to `None`.
+* `paginate_by_param` - The name of a query parameter, which can be used by the client to overide the default page size to use for pagination. If unset this uses the same value as the `PAGINATE_BY_PARAM` setting, which defaults to `None`.
+
## SingleObjectAPIView
Provides a base view for acting on a single object, by combining REST framework's `APIView`, and Django's [SingleObjectMixin].
**See also:** ccbv.co.uk documentation for [SingleObjectMixin][single-object-mixin-classy].
+**Attributes**:
+
+* `queryset` - The queryset that should be used when retrieving an object from this view. If unset, defaults to the default queryset manager for `self.model`.
+* `pk_kwarg` - The URL kwarg that should be used to look up objects by primary key. Defaults to `'pk'`. [Can only be set to non-default on Django 1.4+]
+* `slug_url_kwarg` - The URL kwarg that should be used to look up objects by a slug. Defaults to `'slug'`. [Can only be set to non-default on Django 1.4+]
+* `slug_field` - The field on the model that should be used to look up objects by a slug. If used, this should typically be set to a field with `unique=True`. Defaults to `'slug'`.
+
---
# Mixins
-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 `.get()` and `.post()` directly. This allows for more flexible composition of behaviour.
+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 `.get()` and `.post()` directly. This allows for more flexible composition of behaviour.
## ListModelMixin
Provides a `.list(request, *args, **kwargs)` method, that implements listing a queryset.
+If the queryset is populated, this returns a `200 OK` response, with a serialized representation of the queryset as the body of the response. The response data may optionally be paginated.
+
+If the queryset is empty this returns a `200 OK` reponse, unless the `.allow_empty` attribute on the view is set to `False`, in which case it will return a `404 Not Found`.
+
Should be mixed in with [MultipleObjectAPIView].
## CreateModelMixin
Provides a `.create(request, *args, **kwargs)` method, that implements creating and saving a new model instance.
+If an object is created this returns a `201 Created` response, with a serialized representation of the object as the body of the response. If the representation contains a key named `url`, then the `Location` header of the response will be populated with that value.
+
+If the request data provided for creating the object was invalid, a `400 Bad Request` response will be returned, with the error details as the body of the response.
+
Should be mixed in with any [GenericAPIView].
## RetrieveModelMixin
Provides a `.retrieve(request, *args, **kwargs)` method, that implements returning an existing model instance in a response.
+If an object can be retrieve this returns a `200 OK` response, with a serialized representation of the object as the body of the response. Otherwise it will return a `404 Not Found`.
+
Should be mixed in with [SingleObjectAPIView].
## UpdateModelMixin
Provides a `.update(request, *args, **kwargs)` method, that implements updating and saving an existing model instance.
+If an object is updated this returns a `200 OK` response, with a serialized representation of the object as the body of the response.
+
+If an object is created, for example when making a `DELETE` request followed by a `PUT` request to the same URL, this returns a `201 Created` response, with a serialized representation of the object as the body of the response.
+
+If the request data provided for updating the object was invalid, a `400 Bad Request` response will be returned, with the error details as the body of the response.
+
+A boolean `partial` keyword argument may be supplied to the `.update()` method. If `partial` is set to `True`, all fields for the update will be optional. This allows support for HTTP `PATCH` requests.
+
Should be mixed in with [SingleObjectAPIView].
## DestroyModelMixin
Provides a `.destroy(request, *args, **kwargs)` method, that implements deletion of an existing model instance.
+If an object is deleted this returns a `204 No Content` response, otherwise it will return a `404 Not Found`.
+
Should be mixed in with [SingleObjectAPIView].
[cite]: https://docs.djangoproject.com/en/dev/ref/class-based-views/#base-vs-generic-views
@@ -184,4 +230,4 @@ Should be mixed in with [SingleObjectAPIView].
[CreateModelMixin]: #createmodelmixin
[RetrieveModelMixin]: #retrievemodelmixin
[UpdateModelMixin]: #updatemodelmixin
-[DestroyModelMixin]: #destroymodelmixin \ No newline at end of file
+[DestroyModelMixin]: #destroymodelmixin
diff --git a/docs/api-guide/pagination.md b/docs/api-guide/pagination.md
index 597baba4..ab335e6e 100644
--- a/docs/api-guide/pagination.md
+++ b/docs/api-guide/pagination.md
@@ -70,33 +70,32 @@ We could now use our pagination serializer in a view like this.
# If page is not an integer, deliver first page.
users = paginator.page(1)
except EmptyPage:
- # If page is out of range (e.g. 9999), deliver last page of results.
+ # If page is out of range (e.g. 9999),
+ # deliver last page of results.
users = paginator.page(paginator.num_pages)
serializer_context = {'request': request}
- serializer = PaginatedUserSerializer(instance=users,
+ serializer = PaginatedUserSerializer(users,
context=serializer_context)
return Response(serializer.data)
## Pagination in the generic views
-The generic class based views `ListAPIView` and `ListCreateAPIView` provide pagination of the returned querysets by default. You can customise this behaviour by altering the pagination style, by modifying the default number of results, or by turning pagination off completely.
+The generic class based views `ListAPIView` and `ListCreateAPIView` provide pagination of the returned querysets by default. You can customise this behaviour by altering the pagination style, by modifying the default number of results, by allowing clients to override the page size using a query parameter, or by turning pagination off completely.
-The default pagination style may be set globally, using the `PAGINATION_SERIALIZER` and `PAGINATE_BY` settings. For example.
+The default pagination style may be set globally, using the `DEFAULT_PAGINATION_SERIALIZER_CLASS`, `PAGINATE_BY` and `PAGINATE_BY_PARAM` settings. For example.
REST_FRAMEWORK = {
- 'PAGINATION_SERIALIZER': (
- 'example_app.pagination.CustomPaginationSerializer',
- ),
- 'PAGINATE_BY': 10
+ 'PAGINATE_BY': 10,
+ 'PAGINATE_BY_PARAM': 'page_size'
}
You can also set the pagination style on a per-view basis, using the `ListAPIView` generic class-based view.
class PaginatedListView(ListAPIView):
model = ExampleModel
- pagination_serializer_class = CustomPaginationSerializer
paginate_by = 10
+ paginate_by_param = 'page_size'
For more complex requirements such as serialization that differs depending on the requested media type you can override the `.get_paginate_by()` and `.get_pagination_serializer_class()` methods.
@@ -122,4 +121,20 @@ For example, to nest a pair of links labelled 'prev' and 'next', and set the nam
results_field = 'objects'
+## Using your custom pagination serializer
+
+To have your custom pagination serializer be used by default, use the `DEFAULT_PAGINATION_SERIALIZER_CLASS` setting:
+
+ REST_FRAMEWORK = {
+ 'DEFAULT_PAGINATION_SERIALIZER_CLASS':
+ 'example_app.pagination.CustomPaginationSerializer',
+ }
+
+Alternatively, to set your custom pagination serializer on a per-view basis, use the `pagination_serializer_class` attribute on a generic class based view:
+
+ class PaginatedListView(ListAPIView):
+ model = ExampleModel
+ pagination_serializer_class = CustomPaginationSerializer
+ paginate_by = 10
+
[cite]: https://docs.djangoproject.com/en/dev/topics/pagination/
diff --git a/docs/api-guide/parsers.md b/docs/api-guide/parsers.md
index 185b616c..9356b420 100644
--- a/docs/api-guide/parsers.md
+++ b/docs/api-guide/parsers.md
@@ -159,4 +159,17 @@ For example:
files = {name: uploaded}
return DataAndFiles(data, files)
+---
+
+# Third party packages
+
+The following third party packages are also available.
+
+## MessagePack
+
+[MessagePack][messagepack] is a fast, efficient binary serialization format. [Juan Riaza][juanriaza] maintains the `djangorestframework-msgpack` package which provides MessagePack renderer and parser support for REST framework. Documentation is [available here][djangorestframework-msgpack].
+
[cite]: https://groups.google.com/d/topic/django-developers/dxI4qVzrBY4/discussion
+[messagepack]: https://github.com/juanriaza/django-rest-framework-msgpack
+[juanriaza]: https://github.com/juanriaza
+[djangorestframework-msgpack]: https://github.com/juanriaza/django-rest-framework-msgpack \ No newline at end of file
diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md
index 1a746fb6..fce68f6d 100644
--- a/docs/api-guide/permissions.md
+++ b/docs/api-guide/permissions.md
@@ -53,7 +53,7 @@ You can also set the authentication policy on a per-view basis, using the `APIVi
Or, if you're using the `@api_view` decorator with function based views.
@api_view('GET')
- @permission_classes(IsAuthenticated)
+ @permission_classes((IsAuthenticated, ))
def example_view(request, format=None):
content = {
'status': 'request was permitted'
diff --git a/docs/api-guide/relations.md b/docs/api-guide/relations.md
new file mode 100644
index 00000000..351b5e09
--- /dev/null
+++ b/docs/api-guide/relations.md
@@ -0,0 +1,139 @@
+<a class="github" href="relations.py"></a>
+
+# Serializer relations
+
+> Bad programmers worry about the code.
+> Good programmers worry about data structures and their relationships.
+>
+> &mdash; [Linus Torvalds][cite]
+
+
+Relational fields are used to represent model relationships. They can be applied to `ForeignKey`, `ManyToManyField` and `OneToOneField` relationships, as well as to reverse relationships, and custom relationships such as `GenericForeignKey`.
+
+---
+
+**Note:** The relational fields are declared in `relations.py`, but by convention you should import them using `from rest_framework import serializers` and refer to fields as `serializers.<FieldName>`.
+
+---
+
+## RelatedField
+
+This field can be applied to any of the following:
+
+* A `ForeignKey` field.
+* A `OneToOneField` field.
+* A reverse OneToOne relationship
+* Any other "to-one" relationship.
+
+By default `RelatedField` will represent the target of the field using it's `__unicode__` method.
+
+You can customize this behavior by subclassing `ManyRelatedField`, and overriding the `.to_native(self, value)` method.
+
+## ManyRelatedField
+
+This field can be applied to any of the following:
+
+* A `ManyToManyField` field.
+* A reverse ManyToMany relationship.
+* A reverse ForeignKey relationship
+* Any other "to-many" relationship.
+
+By default `ManyRelatedField` will represent the targets of the field using their `__unicode__` method.
+
+For example, given the following models:
+
+ class TaggedItem(models.Model):
+ """
+ Tags arbitrary model instances using a generic relation.
+
+ See: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/
+ """
+ tag = models.SlugField()
+ content_type = models.ForeignKey(ContentType)
+ object_id = models.PositiveIntegerField()
+ content_object = GenericForeignKey('content_type', 'object_id')
+
+ def __unicode__(self):
+ return self.tag
+
+
+ class Bookmark(models.Model):
+ """
+ A bookmark consists of a URL, and 0 or more descriptive tags.
+ """
+ url = models.URLField()
+ tags = GenericRelation(TaggedItem)
+
+And a model serializer defined like this:
+
+ class BookmarkSerializer(serializers.ModelSerializer):
+ tags = serializers.ManyRelatedField(source='tags')
+
+ class Meta:
+ model = Bookmark
+ exclude = ('id',)
+
+Then an example output format for a Bookmark instance would be:
+
+ {
+ 'tags': [u'django', u'python'],
+ 'url': u'https://www.djangoproject.com/'
+ }
+
+## PrimaryKeyRelatedField
+## ManyPrimaryKeyRelatedField
+
+`PrimaryKeyRelatedField` and `ManyPrimaryKeyRelatedField` will represent the target of the relationship using it's primary key.
+
+By default these fields are read-write, although you can change this behavior using the `read_only` flag.
+
+**Arguments**:
+
+* `queryset` - By default `ModelSerializer` classes will use the default queryset for the relationship. `Serializer` classes must either set a queryset explicitly, or set `read_only=True`.
+* `null` - If set to `True`, the field will accept values of `None` or the empty-string for nullable relationships.
+
+## SlugRelatedField
+## ManySlugRelatedField
+
+`SlugRelatedField` and `ManySlugRelatedField` will represent the target of the relationship using a unique slug.
+
+By default these fields read-write, although you can change this behavior using the `read_only` flag.
+
+**Arguments**:
+
+* `slug_field` - The field on the target that should be used to represent it. This should be a field that uniquely identifies any given instance. For example, `username`.
+* `queryset` - By default `ModelSerializer` classes will use the default queryset for the relationship. `Serializer` classes must either set a queryset explicitly, or set `read_only=True`.
+* `null` - If set to `True`, the field will accept values of `None` or the empty-string for nullable relationships.
+
+## HyperlinkedRelatedField
+## ManyHyperlinkedRelatedField
+
+`HyperlinkedRelatedField` and `ManyHyperlinkedRelatedField` will represent the target of the relationship using a hyperlink.
+
+By default, `HyperlinkedRelatedField` is read-write, although you can change this behavior using the `read_only` flag.
+
+**Arguments**:
+
+* `view_name` - The view name that should be used as the target of the relationship. **required**.
+* `format` - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the `format` argument.
+* `queryset` - By default `ModelSerializer` classes will use the default queryset for the relationship. `Serializer` classes must either set a queryset explicitly, or set `read_only=True`.
+* `slug_field` - The field on the target that should be used for the lookup. Default is `'slug'`.
+* `pk_url_kwarg` - The named url parameter for the pk field lookup. Default is `pk`.
+* `slug_url_kwarg` - The named url parameter for the slug field lookup. Default is to use the same value as given for `slug_field`.
+* `null` - If set to `True`, the field will accept values of `None` or the empty-string for nullable relationships.
+
+## HyperLinkedIdentityField
+
+This field can be applied as an identity relationship, such as the `'url'` field on a HyperlinkedModelSerializer.
+
+This field is always read-only.
+
+**Arguments**:
+
+* `view_name` - The view name that should be used as the target of the relationship. **required**.
+* `format` - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the `format` argument.
+* `slug_field` - The field on the target that should be used for the lookup. Default is `'slug'`.
+* `pk_url_kwarg` - The named url parameter for the pk field lookup. Default is `pk`.
+* `slug_url_kwarg` - The named url parameter for the slug field lookup. Default is to use the same value as given for `slug_field`.
+
+[cite]: http://lwn.net/Articles/193245/
diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md
index 374ff0ab..389dec1f 100644
--- a/docs/api-guide/renderers.md
+++ b/docs/api-guide/renderers.md
@@ -271,6 +271,15 @@ Exceptions raised and handled by an HTML renderer will attempt to render using o
Templates will render with a `RequestContext` which includes the `status_code` and `details` keys.
+---
+
+# Third party packages
+
+The following third party packages are also available.
+
+## MessagePack
+
+[MessagePack][messagepack] is a fast, efficient binary serialization format. [Juan Riaza][juanriaza] maintains the `djangorestframework-msgpack` package which provides MessagePack renderer and parser support for REST framework. Documentation is [available here][djangorestframework-msgpack].
[cite]: https://docs.djangoproject.com/en/dev/ref/template-response/#the-rendering-process
[conneg]: content-negotiation.md
@@ -280,4 +289,7 @@ Templates will render with a `RequestContext` which includes the `status_code` a
[quote]: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
[application/vnd.github+json]: http://developer.github.com/v3/media/
[application/vnd.collection+json]: http://www.amundsen.com/media-types/collection/
-[django-error-views]: https://docs.djangoproject.com/en/dev/topics/http/views/#customizing-error-views \ No newline at end of file
+[django-error-views]: https://docs.djangoproject.com/en/dev/topics/http/views/#customizing-error-views
+[messagepack]: https://github.com/juanriaza/django-rest-framework-msgpack
+[juanriaza]: https://github.com/juanriaza
+[djangorestframework-msgpack]: https://github.com/juanriaza/django-rest-framework-msgpack \ No newline at end of file
diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md
index 0cdae1ce..d98a602f 100644
--- a/docs/api-guide/serializers.md
+++ b/docs/api-guide/serializers.md
@@ -4,8 +4,7 @@
> Expanding the usefulness of the serializers is something that we would
like to address. However, it's not a trivial problem, and it
-will take some serious design work. Any offers to help out in this
-area would be gratefully accepted.
+will take some serious design work.
>
> &mdash; Russell Keith-Magee, [Django users group][cite]
@@ -34,7 +33,7 @@ Declaring a serializer looks very similar to declaring a form:
created = serializers.DateTimeField()
def restore_object(self, attrs, instance=None):
- if instance:
+ if instance is not None:
instance.title = attrs['title']
instance.content = attrs['content']
instance.created = attrs['created']
@@ -77,6 +76,10 @@ When deserializing data, we can either create a new instance, or update an exist
serializer = CommentSerializer(data=data) # Create new instance
serializer = CommentSerializer(comment, data=data) # Update `instance`
+By default, serializers must be passed values for all required fields or they will throw validation errors. You can use the `partial` argument in order to allow partial updates.
+
+ serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True) # Update `instance` with partial data
+
## Validation
When deserializing data, you always need to call `is_valid()` before attempting to access the deserialized object. If any validation errors occur, the `.errors` and `.non_field_errors` properties will contain the resulting error messages.
@@ -106,7 +109,22 @@ Your `validate_<fieldname>` methods should either just return the `attrs` dictio
### Object-level validation
-To do any other validation that requires access to multiple fields, add a method called `.validate()` to your `Serializer` subclass. This method takes a single argument, which is the `attrs` dictionary. It should raise a `ValidationError` if necessary, or just return `attrs`.
+To do any other validation that requires access to multiple fields, add a method called `.validate()` to your `Serializer` subclass. This method takes a single argument, which is the `attrs` dictionary. It should raise a `ValidationError` if necessary, or just return `attrs`. For example:
+
+ from rest_framework import serializers
+
+ class EventSerializer(serializers.Serializer):
+ description = serializers.CahrField(max_length=100)
+ start = serializers.DateTimeField()
+ finish = serializers.DateTimeField()
+
+ def validate(self, attrs):
+ """
+ Check that the start is before the stop.
+ """
+ if attrs['start'] < attrs['finish']:
+ raise serializers.ValidationError("finish must occur after start")
+ return attrs
## Saving object state
@@ -248,6 +266,15 @@ The default `ModelSerializer` uses primary keys for relationships, but you can a
The `depth` option should be set to an integer value that indicates the depth of relationships that should be traversed before reverting to a flat representation.
+## Specifying which fields should be read-only
+
+You may wish to specify multiple fields as read-only. Instead of adding each field explicitely with the `read_only=True` attribute, you may use the `read_only_fields` Meta option, like so:
+
+ class AccountSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = Account
+ read_only_fields = ('created', 'modified')
+
## Customising the default fields
You can create customized subclasses of `ModelSerializer` that use a different set of default fields for the representation, by overriding various `get_<field_type>_field` methods.
diff --git a/docs/api-guide/settings.md b/docs/api-guide/settings.md
index 4f87b30d..8c87f2ca 100644
--- a/docs/api-guide/settings.md
+++ b/docs/api-guide/settings.md
@@ -96,11 +96,21 @@ Default: `rest_framework.serializers.ModelSerializer`
Default: `rest_framework.pagination.PaginationSerializer`
-## FORMAT_SUFFIX_KWARG
+## FILTER_BACKEND
-**TODO**
+The filter backend class that should be used for generic filtering. If set to `None` then generic filtering is disabled.
-Default: `'format'`
+## PAGINATE_BY
+
+The default page size to use for pagination. If set to `None`, pagination is disabled by default.
+
+Default: `None`
+
+## PAGINATE_BY_PARAM
+
+The name of a query parameter, which can be used by the client to overide the default page size to use for pagination. If set to `None`, clients may not override the default page size.
+
+Default: `None`
## UNAUTHENTICATED_USER
@@ -150,4 +160,10 @@ Default: `'accept'`
Default: `'format'`
+## FORMAT_SUFFIX_KWARG
+
+**TODO**
+
+Default: `'format'`
+
[cite]: http://www.python.org/dev/peps/pep-0020/
diff --git a/docs/api-guide/views.md b/docs/api-guide/views.md
index 5b072827..d1e42ec1 100644
--- a/docs/api-guide/views.md
+++ b/docs/api-guide/views.md
@@ -19,6 +19,10 @@ Using the `APIView` class is pretty much the same as using a regular `View` clas
For example:
+ from rest_framework.views import APIView
+ from rest_framework.response import Response
+ from rest_framework import authentication, permissions
+
class ListUsers(APIView):
"""
View to list all users in the system.
diff --git a/docs/index.md b/docs/index.md
index 1874ec00..080eca6f 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -15,7 +15,7 @@ Django REST framework is a lightweight library that makes it easy to build Web A
Web APIs built using REST framework are fully self-describing and web browseable - a huge useability win for your developers. It also supports a wide range of media types, authentication and permission policies out of the box.
-If you are considering using REST framework for your API, we recommend reading the [REST framework 2 announcment][rest-framework-2-announcement] which gives a good overview of the framework and it's capabilities.
+If you are considering using REST framework for your API, we recommend reading the [REST framework 2 announcement][rest-framework-2-announcement] which gives a good overview of the framework and it's capabilities.
There is also a sandbox API you can use for testing purposes, [available here][sandbox].
@@ -32,17 +32,18 @@ REST framework requires the following:
The following packages are optional:
-* [Markdown][markdown] (2.1.0+) - Markdown support for the self describing API.
+* [Markdown][markdown] (2.1.0+) - Markdown support for the browseable API.
* [PyYAML][yaml] (3.10+) - YAML content-type support.
-* [django-filter][django-filter] (master) - Filtering support.
+* [django-filter][django-filter] (0.5.4+) - Filtering support.
## Installation
Install using `pip`, including any optional packages you want...
pip install djangorestframework
- pip install markdown # Recommended if using the browseable API.
- pip install pyyaml # Required for yaml content-type support.
+ pip install markdown # Markdown support for the browseable API.
+ pip install pyyaml # YAML content-type support.
+ pip install django-filter # Filtering support
...or clone the project from github.
@@ -51,21 +52,21 @@ Install using `pip`, including any optional packages you want...
pip install -r requirements.txt
pip install -r optionals.txt
-Add `rest_framework` to your `INSTALLED_APPS`.
+Add `'rest_framework'` to your `INSTALLED_APPS` setting.
INSTALLED_APPS = (
...
'rest_framework',
)
-If you're intending to use the browseable API you'll want to add REST framework's login and logout views. Add the following to your root `urls.py` file.
+If you're intending to use the browseable API you'll probably also want to add REST framework's login and logout views. Add the following to your root `urls.py` file.
urlpatterns = patterns('',
...
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
)
-Note that the URL path can be whatever you want, but you must include `rest_framework.urls` with the `rest_framework` namespace.
+Note that the URL path can be whatever you want, but you must include `'rest_framework.urls'` with the `'rest_framework'` namespace.
## Quickstart
@@ -93,6 +94,7 @@ The API guide is your complete reference manual to all the functionality provide
* [Renderers][renderers]
* [Serializers][serializers]
* [Serializer fields][fields]
+* [Serializer relations][relations]
* [Authentication][authentication]
* [Permissions][permissions]
* [Throttling][throttling]
@@ -136,7 +138,7 @@ Paid support is also available from [DabApps], and can include work on REST fram
## License
-Copyright (c) 2011-2012, Tom Christie
+Copyright (c) 2011-2013, Tom Christie
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -160,7 +162,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[travis]: http://travis-ci.org/tomchristie/django-rest-framework?branch=master
-[travis-build-image]: https://secure.travis-ci.org/tomchristie/django-rest-framework.png?branch=restframework2
+[travis-build-image]: https://secure.travis-ci.org/tomchristie/django-rest-framework.png?branch=master
[urlobject]: https://github.com/zacharyvoase/urlobject
[markdown]: http://pypi.python.org/pypi/Markdown/
[yaml]: http://pypi.python.org/pypi/PyYAML
@@ -184,6 +186,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[renderers]: api-guide/renderers.md
[serializers]: api-guide/serializers.md
[fields]: api-guide/fields.md
+[relations]: api-guide/relations.md
[authentication]: api-guide/authentication.md
[permissions]: api-guide/permissions.md
[throttling]: api-guide/throttling.md
diff --git a/docs/template.html b/docs/template.html
index 676a4807..d789cc58 100644
--- a/docs/template.html
+++ b/docs/template.html
@@ -72,6 +72,7 @@
<li><a href="{{ base_url }}/api-guide/renderers{{ suffix }}">Renderers</a></li>
<li><a href="{{ base_url }}/api-guide/serializers{{ suffix }}">Serializers</a></li>
<li><a href="{{ base_url }}/api-guide/fields{{ suffix }}">Serializer fields</a></li>
+ <li><a href="{{ base_url }}/api-guide/relations{{ suffix }}">Serializer relations</a></li>
<li><a href="{{ base_url }}/api-guide/authentication{{ suffix }}">Authentication</a></li>
<li><a href="{{ base_url }}/api-guide/permissions{{ suffix }}">Permissions</a></li>
<li><a href="{{ base_url }}/api-guide/throttling{{ suffix }}">Throttling</a></li>
diff --git a/docs/topics/credits.md b/docs/topics/credits.md
index 1a2c0db8..83272766 100644
--- a/docs/topics/credits.md
+++ b/docs/topics/credits.md
@@ -2,7 +2,7 @@
The following people have helped make REST framework great.
-* Tom Christie - [tomchristie]
+* Tom Christie - [tomchristie]
* Marko Tibold - [markotibold]
* Paul Bagwell - [pbgwl]
* Sébastien Piquemal - [sebpiq]
@@ -58,6 +58,36 @@ The following people have helped make REST framework great.
* Michael Shepanski - [mjs7231]
* Toni Michel - [tonimichel]
* Ben Konrath - [benkonrath]
+* Marc Aymerich - [glic3rinu]
+* Ludwig Kraatz - [ludwigkraatz]
+* Rob Romano - [robromano]
+* Eugene Mechanism - [mechanism]
+* Jonas Liljestrand - [jonlil]
+* Justin Davis - [irrelative]
+* Dustin Bachrach - [dbachrach]
+* Mark Shirley - [maspwr]
+* Olivier Aubert - [oaubert]
+* Yuri Prezument - [yprez]
+* Fabian Buechler - [fabianbuechler]
+* Mark Hughes - [mhsparks]
+* Michael van de Waeter - [mvdwaeter]
+* Reinout van Rees - [reinout]
+* Michael Richards - [justanotherbody]
+* Ben Roberts - [roberts81]
+* Venkata Subramanian Mahalingam - [annacoder]
+* George Kappel - [gkappel]
+* Colin Murtaugh - [cmurtaugh]
+* Simon Pantzare - [pilt]
+* Szymon Teżewski - [sunscrapers]
+* Joel Marcotte - [joual]
+* Trey Hunner - [treyhunner]
+* Roman Akinfold - [akinfold]
+* Toran Billups - [toranb]
+* Sébastien Béal - [sebastibe]
+* Andrew Hankinson - [ahankinson]
+* Juan Riaza - [juanriaza]
+* Michael Mior - [michaelmior]
+* Marc Tamlyn - [mjtamlyn]
Many thanks to everyone who's contributed to the project.
@@ -69,7 +99,7 @@ Project hosting is with [GitHub].
Continuous integration testing is managed with [Travis CI][travis-ci].
-The [live sandbox][sandbox] is hosted on [Heroku].
+The [live sandbox][sandbox] is hosted on [Heroku].
Various inspiration taken from the [Piston], [Tastypie] and [Dagny] projects.
@@ -77,11 +107,10 @@ Development of REST framework 2.0 was sponsored by [DabApps].
## Contact
-To contact the author directly:
+For usage questions please see the [REST framework discussion group][group].
+
+You can also contact [@_tomchristie][twitter] directly on twitter.
-* twitter: [@_tomchristie][twitter]
-* email: [tom@tomchristie.com][email]
-
[email]: mailto:tom@tomchristie.com
[twitter]: http://twitter.com/_tomchristie
[bootstrap]: http://twitter.github.com/bootstrap/
@@ -94,6 +123,7 @@ To contact the author directly:
[dabapps]: http://lab.dabapps.com
[sandbox]: http://restframework.herokuapp.com/
[heroku]: http://www.heroku.com/
+[group]: https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework
[tomchristie]: https://github.com/tomchristie
[markotibold]: https://github.com/markotibold
@@ -151,3 +181,33 @@ To contact the author directly:
[mjs7231]: https://github.com/mjs7231
[tonimichel]: https://github.com/tonimichel
[benkonrath]: https://github.com/benkonrath
+[glic3rinu]: https://github.com/glic3rinu
+[ludwigkraatz]: https://github.com/ludwigkraatz
+[robromano]: https://github.com/robromano
+[mechanism]: https://github.com/mechanism
+[jonlil]: https://github.com/jonlil
+[irrelative]: https://github.com/irrelative
+[dbachrach]: https://github.com/dbachrach
+[maspwr]: https://github.com/maspwr
+[oaubert]: https://github.com/oaubert
+[yprez]: https://github.com/yprez
+[fabianbuechler]: https://github.com/fabianbuechler
+[mhsparks]: https://github.com/mhsparks
+[mvdwaeter]: https://github.com/mvdwaeter
+[reinout]: https://github.com/reinout
+[justanotherbody]: https://github.com/justanotherbody
+[roberts81]: https://github.com/roberts81
+[annacoder]: https://github.com/annacoder
+[gkappel]: https://github.com/gkappel
+[cmurtaugh]: https://github.com/cmurtaugh
+[pilt]: https://github.com/pilt
+[sunscrapers]: https://github.com/sunscrapers
+[joual]: https://github.com/joual
+[treyhunner]: https://github.com/treyhunner
+[akinfold]: https://github.com/akinfold
+[toranb]: https://github.com/toranb
+[sebastibe]: https://github.com/sebastibe
+[ahankinson]: https://github.com/ahankinson
+[juanriaza]: https://github.com/juanriaza
+[michaelmior]: https://github.com/michaelmior
+[mjtamlyn]: https://github.com/mjtamlyn
diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md
index 670332e6..edd948ac 100644
--- a/docs/topics/release-notes.md
+++ b/docs/topics/release-notes.md
@@ -4,29 +4,159 @@
>
> &mdash; Eric S. Raymond, [The Cathedral and the Bazaar][cite].
-## 2.1.2
+## Versioning
+
+Minor version numbers (0.0.x) are used for changes that are API compatible. You should be able to upgrade between minor point releases without any other code changes.
+
+Medium version numbers (0.x.0) may include minor API changes. You should read the release notes carefully before upgrading between medium point releases.
+
+Major version numbers (x.0.0) are reserved for project milestones. No major point releases are currently planned.
+
+---
+
+## 2.1.x series
+
+### Master
+
+* Deprecate django.utils.simplejson in favor of Python 2.6's built-in json module.
+* Bugfix: Validation errors instead of exceptions when serializers receive incorrect types.
+* Bugfix: Validation errors instead of exceptions when related fields receive incorrect types.
+
+### 2.1.15
+
+**Date**: 3rd Jan 2013
+
+* Added `PATCH` support.
+* Added `RetrieveUpdateAPIView`.
+* Remove unused internal `save_m2m` flag on `ModelSerializer.save()`.
+* Tweak behavior of hyperlinked fields with an explicit format suffix.
+* Relation changes are now persisted in `.save()` instead of in `.restore_object()`.
+* Bugfix: Fix issue with FileField raising exception instead of validation error when files=None.
+* Bugfix: Partial updates should not set default values if field is not included.
+
+### 2.1.14
+
+**Date**: 31st Dec 2012
+
+* Bugfix: ModelSerializers now include reverse FK fields on creation.
+* Bugfix: Model fields with `blank=True` are now `required=False` by default.
+* Bugfix: Nested serializers now support nullable relationships.
+
+**Note**: From 2.1.14 onwards, relational fields move out of the `fields.py` module and into the new `relations.py` module, in order to separate them from regular data type fields, such as `CharField` and `IntegerField`.
+
+This change will not affect user code, so long as it's following the recommended import style of `from rest_framework import serializers` and referring to fields using the style `serializers.PrimaryKeyRelatedField`.
+
+
+### 2.1.13
+
+**Date**: 28th Dec 2012
+
+* Support configurable `STATICFILES_STORAGE` storage.
+* Bugfix: Related fields now respect the required flag, and may be required=False.
+
+### 2.1.12
+
+**Date**: 21st Dec 2012
+
+* Bugfix: Fix bug that could occur using ChoiceField.
+* Bugfix: Fix exception in browseable API on DELETE.
+* Bugfix: Fix issue where pk was was being set to a string if set by URL kwarg.
+
+### 2.1.11
+
+**Date**: 17th Dec 2012
+
+* Bugfix: Fix issue with M2M fields in browseable API.
+
+### 2.1.10
+
+**Date**: 17th Dec 2012
+
+* Bugfix: Ensure read-only fields don't have model validation applied.
+* Bugfix: Fix hyperlinked fields in paginated results.
+
+### 2.1.9
+
+**Date**: 11th Dec 2012
+
+* Bugfix: Fix broken nested serialization.
+* Bugfix: Fix `Meta.fields` only working as tuple not as list.
+* Bugfix: Edge case if unnecessarily specifying `required=False` on read only field.
+
+### 2.1.8
+
+**Date**: 8th Dec 2012
+
+* Fix for creating nullable Foreign Keys with `''` as well as `None`.
+* Added `null=<bool>` related field option.
+
+### 2.1.7
+
+**Date**: 7th Dec 2012
+
+* Serializers now properly support nullable Foreign Keys.
+* Serializer validation now includes model field validation, such as uniqueness constraints.
+* Support 'true' and 'false' string values for BooleanField.
+* Added pickle support for serialized data.
+* Support `source='dotted.notation'` style for nested serializers.
+* Make `Request.user` settable.
+* Bugfix: Fix `RegexField` to work with `BrowsableAPIRenderer`.
+
+### 2.1.6
+
+**Date**: 23rd Nov 2012
+
+* Bugfix: Unfix DjangoModelPermissions. (I am a doofus.)
+
+### 2.1.5
+
+**Date**: 23rd Nov 2012
+
+* Bugfix: Fix DjangoModelPermissions.
+
+### 2.1.4
+
+**Date**: 22nd Nov 2012
+
+* Support for partial updates with serializers.
+* Added `RegexField`.
+* Added `SerializerMethodField`.
+* Serializer performance improvements.
+* Added `obtain_token_view` to get tokens when using `TokenAuthentication`.
+* Bugfix: Django 1.5 configurable user support for `TokenAuthentication`.
+
+### 2.1.3
+
+**Date**: 16th Nov 2012
+
+* Added `FileField` and `ImageField`. For use with `MultiPartParser`.
+* Added `URLField` and `SlugField`.
+* Support for `read_only_fields` on `ModelSerializer` classes.
+* Support for clients overriding the pagination page sizes. Use the `PAGINATE_BY_PARAM` setting or set the `paginate_by_param` attribute on a generic view.
+* 201 Responses now return a 'Location' header.
+* Bugfix: Serializer fields now respect `max_length`.
+
+### 2.1.2
**Date**: 9th Nov 2012
* **Filtering support.**
* Bugfix: Support creation of objects with reverse M2M relations.
-## 2.1.1
+### 2.1.1
**Date**: 7th Nov 2012
* Support use of HTML exception templates. Eg. `403.html`
* Hyperlinked fields take optional `slug_field`, `slug_url_kwarg` and `pk_url_kwarg` arguments.
-* Bugfix: Deal with optional trailing slashs properly when generating breadcrumbs.
+* Bugfix: Deal with optional trailing slashes properly when generating breadcrumbs.
* Bugfix: Make textareas same width as other fields in browsable API.
* Private API change: `.get_serializer` now uses same `instance` and `data` ordering as serializer initialization.
-## 2.1.0
+### 2.1.0
**Date**: 5th Nov 2012
-**Warning**: Please read [this thread][2.1.0-notes] regarding the `instance` and `data` keyword args before updating to 2.1.0.
-
* **Serializer `instance` and `data` keyword args have their position swapped.**
* `queryset` argument is now optional on writable model fields.
* Hyperlinked related fields optionally take `slug_field` and `slug_url_kwarg` arguments.
@@ -35,13 +165,19 @@
* Bugfix: Support choice field in Browseable API.
* Bugfix: Related fields with `read_only=True` do not require a `queryset` argument.
-## 2.0.2
+**API-incompatible changes**: Please read [this thread][2.1.0-notes] regarding the `instance` and `data` keyword args before updating to 2.1.0.
+
+---
+
+## 2.0.x series
+
+### 2.0.2
**Date**: 2nd Nov 2012
* Fix issues with pk related fields in the browsable API.
-## 2.0.1
+### 2.0.1
**Date**: 1st Nov 2012
@@ -49,7 +185,7 @@
* Added SlugRelatedField and ManySlugRelatedField.
* If PUT creates an instance return '201 Created', instead of '200 OK'.
-## 2.0.0
+### 2.0.0
**Date**: 30th Oct 2012
@@ -58,34 +194,40 @@
---
-## 0.4.0
+## 0.4.x series
+
+### 0.4.0
* Supports Django 1.5.
* Fixes issues with 'HEAD' method.
* Allow views to specify template used by TemplateRenderer
* More consistent error responses
* Some serializer fixes
-* Fix internet explorer ajax behaviour
+* Fix internet explorer ajax behavior
* Minor xml and yaml fixes
-* Improve setup (eg use staticfiles, not the defunct ADMIN_MEDIA_PREFIX)
+* Improve setup (e.g. use staticfiles, not the defunct ADMIN_MEDIA_PREFIX)
* Sensible absolute URL generation, not using hacky set_script_prefix
-## 0.3.3
+---
+
+## 0.3.x series
+
+### 0.3.3
* Added DjangoModelPermissions class to support `django.contrib.auth` style permissions.
* Use `staticfiles` for css files.
- - Easier to override. Won't conflict with customised admin styles (eg grappelli)
+ - Easier to override. Won't conflict with customized admin styles (e.g. grappelli)
* Templates are now nicely namespaced.
- Allows easier overriding.
* Drop implied 'pk' filter if last arg in urlconf is unnamed.
- - Too magical. Explict is better than implicit.
-* Saner template variable autoescaping.
-* Tider setup.py
+ - Too magical. Explicit is better than implicit.
+* Saner template variable auto-escaping.
+* Tidier setup.py
* Updated for URLObject 2.0
* Bugfixes:
- Bug with PerUserThrottling when user contains unicode chars.
-## 0.3.2
+### 0.3.2
* Bugfixes:
* Fix 403 for POST and PUT from the UI with UserLoggedInAuthentication (#115)
@@ -97,37 +239,41 @@
* get_name, get_description become methods on the view - makes them overridable.
* Improved model mixin API - Hooks for build_query, get_instance_data, get_model, get_queryset, get_ordering
-## 0.3.1
+### 0.3.1
* [not documented]
-## 0.3.0
+### 0.3.0
* JSONP Support
* Bugfixes, including support for latest markdown release
-## 0.2.4
+---
+
+## 0.2.x series
+
+### 0.2.4
* Fix broken IsAdminUser permission.
* OPTIONS support.
* XMLParser.
* Drop mentions of Blog, BitBucket.
-## 0.2.3
+### 0.2.3
* Fix some throttling bugs.
* ``X-Throttle`` header on throttling.
* Support for nesting resources on related models.
-## 0.2.2
+### 0.2.2
* Throttling support complete.
-## 0.2.1
+### 0.2.1
* Couple of simple bugfixes over 0.2.0
-## 0.2.0
+### 0.2.0
* Big refactoring changes since 0.1.0, ask on the discussion group if anything isn't clear.
The public API has been massively cleaned up. Expect it to be fairly stable from here on in.
@@ -151,14 +297,20 @@
* The mixin classes have been nicely refactored, the basic mixins are now ``RequestMixin``, ``ResponseMixin``, ``AuthMixin``, and ``ResourceMixin``
You can reuse these mixin classes individually without using the ``View`` class.
-## 0.1.1
+---
+
+## 0.1.x series
+
+### 0.1.1
* Final build before pulling in all the refactoring changes for 0.2, in case anyone needs to hang on to 0.1.
-## 0.1.0
+### 0.1.0
* Initial release.
[cite]: http://www.catb.org/~esr/writings/cathedral-bazaar/cathedral-bazaar/ar01s04.html
+[staticfiles14]: https://docs.djangoproject.com/en/1.4/howto/static-files/#with-a-template-tag
+[staticfiles13]: https://docs.djangoproject.com/en/1.3/howto/static-files/#with-a-template-tag
[2.1.0-notes]: https://groups.google.com/d/topic/django-rest-framework/Vv2M0CMY9bg/discussion
[announcement]: rest-framework-2-announcement.md
diff --git a/docs/topics/rest-hypermedia-hateoas.md b/docs/topics/rest-hypermedia-hateoas.md
index d7646892..10ab9dfe 100644
--- a/docs/topics/rest-hypermedia-hateoas.md
+++ b/docs/topics/rest-hypermedia-hateoas.md
@@ -32,7 +32,7 @@ REST framework also includes [serialization] and [parser]/[renderer] components
## What REST framework doesn't provide.
-What REST framework doesn't do is give you is machine readable hypermedia formats such as [Collection+JSON][collection] or HTML [microformats] by default, or the ability to auto-magically create fully HATEOAS style APIs that include hypermedia-based form descriptions and semantically labelled hyperlinks. Doing so would involve making opinionated choices about API design that should really remain outside of the framework's scope.
+What REST framework doesn't do is give you is machine readable hypermedia formats such as [HAL][hal], [Collection+JSON][collection] or HTML [microformats] by default, or the ability to auto-magically create fully HATEOAS style APIs that include hypermedia-based form descriptions and semantically labelled hyperlinks. Doing so would involve making opinionated choices about API design that should really remain outside of the framework's scope.
[cite]: http://vimeo.com/channels/restfest/page:2
[dissertation]: http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
@@ -44,6 +44,7 @@ What REST framework doesn't do is give you is machine readable hypermedia format
[readinglist]: http://blog.steveklabnik.com/posts/2012-02-27-hypermedia-api-reading-list
[maturitymodel]: http://martinfowler.com/articles/richardsonMaturityModel.html
+[hal]: http://stateless.co/hal_specification.html
[collection]: http://www.amundsen.com/media-types/collection/
[microformats]: http://microformats.org/wiki/Main_Page
[serialization]: ../api-guide/serializers.md
diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md
index ba64f2aa..e61fb946 100644
--- a/docs/tutorial/1-serialization.md
+++ b/docs/tutorial/1-serialization.md
@@ -14,7 +14,7 @@ The tutorial is fairly in-depth, so you should probably get a cookie and a cup o
## Setting up a new environment
-Before we do anything else we'll create a new virtual environment, using [virtualenv]. This will make sure our package configuration is keep nicely isolated from any other projects we're working on.
+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
mkdir ~/env
@@ -39,7 +39,6 @@ To get started, let's create a new project to work with.
cd tutorial
Once that's done we can create an app that we'll use to create a simple Web API.
-We're going to create a project that
python manage.py startapp snippets
@@ -64,7 +63,7 @@ We'll also need to add our new `snippets` app and the `rest_framework` app to `I
'snippets'
)
-We also need to wire up the root urlconf, in the `tutorial/urls.py` file, to include our snippet views.
+We also need to wire up the root urlconf, in the `tutorial/urls.py` file, to include our snippet app's URLs.
urlpatterns = patterns('',
url(r'^', include('snippets.urls')),
@@ -105,7 +104,7 @@ Don't forget to sync the database for the first time.
## Creating a Serializer class
-The first thing we need to get started on our Web API is provide a way of serializing and deserializing the snippet instances into representations such as `json`. We can do this by declaring serializers that work very similarly to Django's forms. Create a file in the `snippets` directory named `serializers.py` and add the following.
+The first thing we need to get started on our Web API is provide a way of serializing and deserializing the snippet instances into representations such as `json`. We can do this by declaring serializers that work very similar to Django's forms. Create a file in the `snippets` directory named `serializers.py` and add the following.
from django.forms import widgets
from rest_framework import serializers
@@ -146,7 +145,7 @@ We can actually also save ourselves some time by using the `ModelSerializer` cla
## Working with Serializers
-Before we go any further we'll familiarise ourselves with using our new Serializer class. Let's drop into the Django shell.
+Before we go any further we'll familiarize ourselves with using our new Serializer class. Let's drop into the Django shell.
python manage.py shell
@@ -166,7 +165,7 @@ We've now got a few snippet instances to play with. Let's take a look at serial
serializer.data
# {'pk': 1, '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 finalise the serialization process we render the data into `json`.
+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
@@ -292,7 +291,7 @@ Finally we need to wire these views up. Create the `snippets/urls.py` file:
url(r'^snippets/(?P<pk>[0-9]+)/$', 'snippet_detail')
)
-It's worth noting that there's a couple of edge cases we're not dealing with properly at the moment. If we send malformed `json`, or if a request is made with a method that the view doesn't handle, then we'll end up with a 500 "server error" response. Still, this'll do for now.
+It's worth noting that there are a couple of edge cases we're not dealing with properly at the moment. If we send malformed `json`, or if a request is made with a method that the view doesn't handle, then we'll end up with a 500 "server error" response. Still, this'll do for now.
## Testing our first attempt at a Web API
@@ -304,7 +303,7 @@ It's worth noting that there's a couple of edge cases we're not dealing with pro
We're doing okay so far, we've got a serialization API that feels pretty similar to Django's Forms API, and some regular Django views.
-Our API views don't do anything particularly special at the moment, beyond serve `json` responses, and there's some error handling edge cases we'd still like to clean up, but it's a functioning Web API.
+Our API views don't do anything particularly special at the moment, beyond serving `json` responses, and there are some error handling edge cases we'd still like to clean up, but it's a functioning Web API.
We'll see how we can start to improve things in [part 2 of the tutorial][tut-2].
diff --git a/docs/tutorial/2-requests-and-responses.md b/docs/tutorial/2-requests-and-responses.md
index b29daf05..08cf91cd 100644
--- a/docs/tutorial/2-requests-and-responses.md
+++ b/docs/tutorial/2-requests-and-responses.md
@@ -41,8 +41,8 @@ We don't need our `JSONResponse` class anymore, so go ahead and delete that. On
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
- from snippet.models import Snippet
- from snippet.serializers import SnippetSerializer
+ from snippets.models import Snippet
+ from snippets.serializers import SnippetSerializer
@api_view(['GET', 'POST'])
@@ -66,6 +66,8 @@ We don't need our `JSONResponse` class anymore, so go ahead and delete that. On
Our instance view is an improvement over the previous example. It's a little more concise, and the code now feels very similar to if we were working with the Forms API. We're also using named status codes, which makes the response meanings more obvious.
+Here is the view for an individual snippet.
+
@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
"""
@@ -92,7 +94,7 @@ Our instance view is an improvement over the previous example. It's a little mo
snippet.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
-This should all feel very familiar - there's not a lot different to working with regular Django views.
+This should all feel very familiar - it is not a lot different from working with regular Django views.
Notice that we're no longer explicitly tying our requests or responses to a given content type. `request.DATA` can handle incoming `json` requests, but it can also handle `yaml` and other formats. Similarly we're returning response objects with data, but allowing REST framework to render the response into the correct content type for us.
@@ -113,7 +115,7 @@ Now update the `urls.py` file slightly, to append a set of `format_suffix_patter
from django.conf.urls import patterns, url
from rest_framework.urlpatterns import format_suffix_patterns
- urlpatterns = patterns('snippet.views',
+ urlpatterns = patterns('snippets.views',
url(r'^snippets/$', 'snippet_list'),
url(r'^snippets/(?P<pk>[0-9]+)$', 'snippet_detail')
)
@@ -128,7 +130,7 @@ Go ahead and test the API from the command line, as we did in [tutorial part 1][
**TODO: Describe using accept headers, content-type headers, and format suffixed URLs**
-Now go and open the API in a web browser, by visiting [http://127.0.0.1:8000/snippets/][devserver]."
+Now go and open the API in a web browser, by visiting [http://127.0.0.1:8000/snippets/][devserver].
### Browsability
diff --git a/docs/tutorial/3-class-based-views.md b/docs/tutorial/3-class-based-views.md
index eddf6311..b115b022 100644
--- a/docs/tutorial/3-class-based-views.md
+++ b/docs/tutorial/3-class-based-views.md
@@ -6,8 +6,8 @@ We can also write our API views using class based views, rather than function ba
We'll start by rewriting the root view as a class based view. All this involves is a little bit of refactoring.
- from snippet.models import Snippet
- from snippet.serializers import SnippetSerializer
+ from snippets.models import Snippet
+ from snippets.serializers import SnippetSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
@@ -66,7 +66,7 @@ We'll also need to refactor our URLconf slightly now we're using class based vie
from django.conf.urls import patterns, url
from rest_framework.urlpatterns import format_suffix_patterns
- from snippetpost import views
+ from snippets import views
urlpatterns = patterns('',
url(r'^snippets/$', views.SnippetList.as_view()),
@@ -85,8 +85,8 @@ The create/retrieve/update/delete operations that we've been using so far are go
Let's take a look at how we can compose our views by using the mixin classes.
- from snippet.models import Snippet
- from snippet.serializers import SnippetSerializer
+ from snippets.models import Snippet
+ from snippets.serializers import SnippetSerializer
from rest_framework import mixins
from rest_framework import generics
@@ -102,14 +102,14 @@ Let's take a look at how we can compose our views by using the mixin classes.
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
-We'll take a moment to examine exactly what's happening here - We're building our view using `MultipleObjectAPIView`, and adding in `ListModelMixin` and `CreateModelMixin`.
+We'll take a moment to examine exactly what's happening here. We're building our view using `MultipleObjectAPIView`, and adding in `ListModelMixin` and `CreateModelMixin`.
The base class provides the core functionality, and the mixin classes provide the `.list()` and `.create()` actions. We're then explicitly binding the `get` and `post` methods to the appropriate actions. Simple enough stuff so far.
class SnippetDetail(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
- generics.SingleObjectBaseView):
+ generics.SingleObjectAPIView):
model = Snippet
serializer_class = SnippetSerializer
@@ -122,14 +122,14 @@ The base class provides the core functionality, and the mixin classes provide th
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
-Pretty similar. This time we're using the `SingleObjectBaseView` class to provide the core functionality, and adding in mixins to provide the `.retrieve()`, `.update()` and `.destroy()` actions.
+Pretty similar. This time we're using the `SingleObjectAPIView` class to provide the core functionality, and adding in mixins to provide the `.retrieve()`, `.update()` and `.destroy()` actions.
## Using generic class based views
Using the mixin classes we've rewritten the views to use slightly less code than before, but we can go one step further. REST framework provides a set of already mixed-in generic views that we can use.
- from snippet.models import Snippet
- from snippet.serializers import SnippetSerializer
+ from snippets.models import Snippet
+ from snippets.serializers import SnippetSerializer
from rest_framework import generics
@@ -142,7 +142,7 @@ Using the mixin classes we've rewritten the views to use slightly less code than
model = Snippet
serializer_class = SnippetSerializer
-Wow, that's pretty concise. We've got a huge amount for free, and our code looks like good, clean, idiomatic Django.
+Wow, that's pretty concise. We've gotten a huge amount for free, and our code looks like good, clean, idiomatic Django.
Next we'll move onto [part 4 of the tutorial][tut-4], where we'll take a look at how we can deal with authentication and permissions for our API.
diff --git a/docs/tutorial/4-authentication-and-permissions.md b/docs/tutorial/4-authentication-and-permissions.md
index f85250be..9576a7f0 100644
--- a/docs/tutorial/4-authentication-and-permissions.md
+++ b/docs/tutorial/4-authentication-and-permissions.md
@@ -61,7 +61,7 @@ Now that we've got some users to work with, we'd better add representations of t
model = User
fields = ('id', 'username', 'snippets')
-Because `'snippets'` is a *reverse* relationship on the User model, it will not be included by default when using the `ModelSerializer` class, so we've needed to add an explicit field for it.
+Because `'snippets'` is a *reverse* relationship on the User model, it will not be included by default when using the `ModelSerializer` class, so we needed to add an explicit field for it.
We'll also add a couple of views. We'd like to just use read-only views for the user representations, so we'll use the `ListAPIView` and `RetrieveAPIView` generic class based views.
@@ -92,9 +92,7 @@ On **both** the `SnippetList` and `SnippetDetail` view classes, add the followin
## Updating our serializer
-Now that snippets are associated with the user that created them, let's update our SnippetSerializer to reflect that.
-
-Add the following field to the serializer definition:
+Now that snippets are associated with the user that created them, let's update our `SnippetSerializer` to reflect that. Add the following field to the serializer definition:
owner = serializers.Field(source='owner.username')
@@ -108,7 +106,7 @@ The field we've added is the untyped `Field` class, in contrast to the other typ
## 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.
+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.
REST framework includes a number of permission classes that we can use to restrict who can access a given view. In this case the one we're looking for is `IsAuthenticatedOrReadOnly`, which will ensure that authenticated requests get read-write access, and unauthenticated requests get read-only access.
diff --git a/docs/tutorial/5-relationships-and-hyperlinked-apis.md b/docs/tutorial/5-relationships-and-hyperlinked-apis.md
index 98c45b82..216ca433 100644
--- a/docs/tutorial/5-relationships-and-hyperlinked-apis.md
+++ b/docs/tutorial/5-relationships-and-hyperlinked-apis.md
@@ -25,7 +25,7 @@ Notice that we're using REST framework's `reverse` function in order to return f
The other obvious thing that's still missing from our pastebin API is the code highlighting endpoints.
-Unlike all our other API endpoints, we don't want to use JSON, but instead just present an HTML representation. There are two style of HTML renderer provided by REST framework, one for dealing with HTML rendered using templates, the other for dealing with pre-rendered HTML. The second renderer is the one we'd like to use for this endpoint.
+Unlike all our other API endpoints, we don't want to use JSON, but instead just present an HTML representation. There are two styles of HTML renderer provided by REST framework, one for dealing with HTML rendered using templates, the other for dealing with pre-rendered HTML. The second renderer is the one we'd like to use for this endpoint.
The other thing we need to consider when creating the code highlight view is that there's no existing concrete generic view that we can use. We're not returning an object instance, but instead a property of an object instance.
@@ -151,7 +151,7 @@ We could also customize the pagination style if we needed too, but in this case
If we open a browser and navigate to the browseable API, you'll find that you can now work your way around the API simply by following links.
-You'll also be able to see the 'highlight' links on the snippet instances, that will take you to the hightlighted code HTML representations.
+You'll also be able to see the 'highlight' links on the snippet instances, that will take you to the highlighted code HTML representations.
We've now got a complete pastebin Web API, which is fully web browseable, and comes complete with authentication, per-object permissions, and multiple renderer formats.
@@ -163,9 +163,9 @@ You can review the final [tutorial code][repo] on GitHub, or try out a live exam
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:
-* Contribute on [GitHub][github] by reviewing and subitting issues, and making pull requests.
+* 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 on Twitter][twitter] and say hi.
**Now go build awesome things.**
diff --git a/docs/tutorial/quickstart.md b/docs/tutorial/quickstart.md
index 93da1a59..74084541 100644
--- a/docs/tutorial/quickstart.md
+++ b/docs/tutorial/quickstart.md
@@ -8,7 +8,7 @@ Create a new Django project, and start a new app called `quickstart`. Once you'
First up we're going to define some serializers in `quickstart/serializers.py` that we'll use for our data representations.
- from django.contrib.auth.models import User, Group
+ from django.contrib.auth.models import User, Group, Permission
from rest_framework import serializers
@@ -137,7 +137,7 @@ We'd also like to set a few global settings. We'd like to turn on pagination, a
'PAGINATE_BY': 10
}
-Okay, that's us done.
+Okay, we're done.
---