aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/api-guide/authentication.md6
-rw-r--r--docs/api-guide/content-negotiation.md57
-rw-r--r--docs/api-guide/exceptions.md4
-rw-r--r--docs/api-guide/fields.md8
-rw-r--r--docs/api-guide/format-suffixes.md52
-rw-r--r--docs/api-guide/pagination.md6
-rw-r--r--docs/api-guide/parsers.md8
-rw-r--r--docs/api-guide/permissions.md6
-rw-r--r--docs/api-guide/renderers.md8
-rw-r--r--docs/api-guide/requests.md14
-rw-r--r--docs/api-guide/responses.md2
-rw-r--r--docs/api-guide/reverse.md2
-rw-r--r--docs/api-guide/serializers.md4
-rw-r--r--docs/api-guide/settings.md20
-rw-r--r--docs/api-guide/throttling.md14
-rw-r--r--docs/api-guide/views.md4
-rw-r--r--docs/css/default.css4
-rw-r--r--docs/index.md4
-rw-r--r--docs/topics/csrf.md4
-rw-r--r--docs/topics/rest-hypermedia-hateoas.md6
-rw-r--r--docs/tutorial/2-requests-and-responses.md2
-rw-r--r--docs/tutorial/3-class-based-views.md2
-rw-r--r--docs/tutorial/6-resource-orientated-projects.md2
-rw-r--r--docs/tutorial/quickstart.md4
-rw-r--r--rest_framework/fields.py5
-rw-r--r--rest_framework/generics.py4
-rw-r--r--rest_framework/request.py2
-rw-r--r--rest_framework/serializers.py23
-rw-r--r--rest_framework/settings.py43
-rw-r--r--rest_framework/tests/models.py11
-rw-r--r--rest_framework/tests/serializer.py60
-rw-r--r--rest_framework/throttling.py4
-rw-r--r--rest_framework/urlpatterns.py13
-rw-r--r--rest_framework/views.py12
34 files changed, 298 insertions, 122 deletions
diff --git a/docs/api-guide/authentication.md b/docs/api-guide/authentication.md
index 71f48163..7bad4867 100644
--- a/docs/api-guide/authentication.md
+++ b/docs/api-guide/authentication.md
@@ -26,10 +26,10 @@ The value of `request.user` and `request.auth` for unauthenticated requests can
## Setting the authentication policy
-The default authentication policy may be set globally, using the `DEFAULT_AUTHENTICATION` setting. For example.
+The default authentication policy may be set globally, using the `DEFAULT_AUTHENTICATION_CLASSES` setting. For example.
REST_FRAMEWORK = {
- 'DEFAULT_AUTHENTICATION': (
+ 'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.UserBasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
)
@@ -86,7 +86,7 @@ You'll also need to create tokens for your users.
token = Token.objects.create(user=...)
print token.key
-For clients to authenticate, the token key should be included in the `Authorization` HTTP header. The key should be prefixed by the string literal "Token", with whitespace seperating the two strings. For example:
+For clients to authenticate, the token key should be included in the `Authorization` HTTP header. The key should be prefixed by the string literal "Token", with whitespace separating the two strings. For example:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
diff --git a/docs/api-guide/content-negotiation.md b/docs/api-guide/content-negotiation.md
index b95091c5..10288c94 100644
--- a/docs/api-guide/content-negotiation.md
+++ b/docs/api-guide/content-negotiation.md
@@ -8,8 +8,59 @@
[cite]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html
-**TODO**: Describe content negotiation style used by REST framework.
+Content negotiation is the process of selecting one of multiple possible representations to return to a client, based on client or server preferences.
-## Custom content negotiation
+## Determining the accepted renderer
-It's unlikley that you'll want to provide a custom content negotiation scheme for REST framework, but you can do so if needed. To implement a custom content negotiation scheme, override `BaseContentNegotiation`, and implement the `.select_parser(request, parsers)` and `.select_renderer(request, renderers, format_suffix)` \ No newline at end of file
+REST framework uses a simple style of content negotiation to determine which media type should be returned to a client, based on the available renderers, the priorities of each of those renderers, and the client's `Accept:` header. The style used is partly client-driven, and partly server-driven.
+
+1. More specific media types are given preference to less specific media types.
+2. If multiple media types have the same specificity, then preference is given to based on the ordering of the renderers configured for the given view.
+
+For example, given the following `Accept` header:
+
+ application/json; indent=4, application/json, application/yaml, text/html, */*
+
+The priorities for each of the given media types would be:
+
+* `application/json; indent=4`
+* `application/json`, `application/yaml` and `text/html`
+* `*/*`
+
+If the requested view was only configured with renderers for `YAML` and `HTML`, then REST framework would select whichever renderer was listed first in the `renderer_classes` list or `DEFAULT_RENDERER_CLASSES` setting.
+
+For more information on the `HTTP Accept` header, see [RFC 2616][accept-header]
+
+---
+
+**Note**: "q" values are not taken into account by REST framework when determining preference. The use of "q" values negatively impacts caching, and in the author's opinion they are an unnecessary and overcomplicated approach to content negotiation.
+
+This is a valid approach as the HTTP spec deliberately underspecifies how a server should weight server-based preferences against client-based preferences.
+
+---
+
+# Custom content negotiation
+
+It's unlikely that you'll want to provide a custom content negotiation scheme for REST framework, but you can do so if needed. To implement a custom content negotiation scheme override `BaseContentNegotiation`.
+
+REST framework's content negotiation classes handle selection of both the appropriate parser for the request, and the appropriate renderer for the response, so you should implement both the `.select_parser(request, parsers)` and `.select_renderer(request, renderers, format_suffix)` methods.
+
+## Example
+
+The following is a custom content negotiation class which ignores the client
+request when selecting the appropriate parser or renderer.
+
+ class IgnoreClientContentNegotiation(BaseContentNegotiation):
+ def select_parser(self, request, parsers):
+ """
+ Select the first parser in the `.parser_classes` list.
+ """
+ return parsers[0]
+
+ def select_renderer(self, request, renderers, format_suffix):
+ """
+ Select the first renderer in the `.renderer_classes` list.
+ """
+ return renderers[0]
+
+[accept-header]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
diff --git a/docs/api-guide/exceptions.md b/docs/api-guide/exceptions.md
index 33cf1ca8..ba57fde8 100644
--- a/docs/api-guide/exceptions.md
+++ b/docs/api-guide/exceptions.md
@@ -25,7 +25,7 @@ For example, the following request:
DELETE http://api.example.com/foo/bar HTTP/1.1
Accept: application/json
-Might recieve an error response indicating that the `DELETE` method is not allowed on that resource:
+Might receive an error response indicating that the `DELETE` method is not allowed on that resource:
HTTP/1.1 405 Method Not Allowed
Content-Type: application/json; charset=utf-8
@@ -85,4 +85,4 @@ Raised when an incoming request fails the throttling checks.
By default this exception results in a response with the HTTP status code "429 Too Many Requests".
-[cite]: http://www.doughellmann.com/articles/how-tos/python-exception-handling/index.html \ No newline at end of file
+[cite]: http://www.doughellmann.com/articles/how-tos/python-exception-handling/index.html
diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md
index 234c65ad..189ed76f 100644
--- a/docs/api-guide/fields.md
+++ b/docs/api-guide/fields.md
@@ -42,7 +42,7 @@ A serializer definition that looked like this:
class Meta:
fields = ('url', 'owner', 'name', 'expired')
-Would produced output similar to:
+Would produce output similar to:
{
'url': 'http://example.com/api/accounts/3/',
@@ -51,7 +51,7 @@ Would produced output similar to:
'expired': True
}
-Be 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 neccesary.
+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.
You can customize this behaviour by overriding the `.to_native(self, value)` method.
@@ -92,7 +92,7 @@ A field that can accept on of a limited set of choices.
## EmailField
-A text representation, validates the text to be a valid e-mail adress.
+A text representation, validates the text to be a valid e-mail address.
Corresponds to `django.db.models.fields.EmailField`
@@ -183,7 +183,7 @@ And a model serializer defined like this:
model = Bookmark
exclude = ('id',)
-The an example output format for a Bookmark instance would be:
+Then an example output format for a Bookmark instance would be:
{
'tags': [u'django', u'python'],
diff --git a/docs/api-guide/format-suffixes.md b/docs/api-guide/format-suffixes.md
index 7d72d9f8..6d5feba4 100644
--- a/docs/api-guide/format-suffixes.md
+++ b/docs/api-guide/format-suffixes.md
@@ -7,5 +7,55 @@ used all the time.
>
> — Roy Fielding, [REST discuss mailing list][cite]
-[cite]: http://tech.groups.yahoo.com/group/rest-discuss/message/5857
+A common pattern for Web APIs is to use filename extensions on URLs to provide an endpoint for a given media type. For example, 'http://example.com/api/users.json' to serve a JSON representation.
+
+Adding format-suffix patterns to each individual entry in the URLconf for your API is error-prone and non-DRY, so REST framework provides a shortcut to adding these patterns to your URLConf.
+
+## format_suffix_patterns
+
+**Signature**: format_suffix_patterns(urlpatterns, suffix_required=False, allowed=None)
+
+Returns a URL pattern list which includes format suffix patterns appended to each of the URL patterns provided.
+
+Arguments:
+
+* **urlpatterns**: Required. A URL pattern list.
+* **suffix_required**: Optional. A boolean indicating if suffixes in the URLs should be optional or mandatory. Defaults to `False`, meaning that suffixes are optional by default.
+* **allowed**: Optional. A list or tuple of valid format suffixes. If not provided, a wildcard format suffix pattern will be used.
+
+Example:
+
+ from rest_framework.urlpatterns import format_suffix_patterns
+
+ urlpatterns = patterns('blog.views',
+ url(r'^/$', 'api_root'),
+ url(r'^comment/$', 'comment_root'),
+ url(r'^comment/(?P<pk>[0-9]+)/$', 'comment_instance')
+ )
+
+ urlpatterns = format_suffix_patterns(urlpatterns, allowed=['json', 'html'])
+
+When using `format_suffix_patterns`, you must make sure to add the `'format'` keyword argument to the corresponding views. For example.
+ @api_view(('GET',))
+ def api_root(request, format=None):
+ # do stuff...
+
+The name of the kwarg used may be modified by using the `FORMAT_SUFFIX_KWARG` setting.
+
+Also note that `format_suffix_patterns` does not support descending into `include` URL patterns.
+
+---
+
+## Accept headers vs. format suffixes
+
+There seems to be a view among some of the Web community that filename extensions are not a RESTful pattern, and that `HTTP Accept` headers should always be used instead.
+
+It is actually a misconception. For example, take the following quote from Roy Fielding discussing the relative merits of query parameter media-type indicators vs. file extension media-type indicators:
+
+&ldquo;That's why I always prefer extensions. Neither choice has anything to do with REST.&rdquo; &mdash; Roy Fielding, [REST discuss mailing list][cite2]
+
+The quote does not mention Accept headers, but it does make it clear that format suffixes should be considered an acceptable pattern.
+
+[cite]: http://tech.groups.yahoo.com/group/rest-discuss/message/5857
+[cite2]: http://tech.groups.yahoo.com/group/rest-discuss/message/14844 \ No newline at end of file
diff --git a/docs/api-guide/pagination.md b/docs/api-guide/pagination.md
index e416de02..597baba4 100644
--- a/docs/api-guide/pagination.md
+++ b/docs/api-guide/pagination.md
@@ -100,12 +100,16 @@ You can also set the pagination style on a per-view basis, using the `ListAPIVie
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.
-## Custom pagination serializers
+---
+
+# Custom pagination serializers
To create a custom pagination serializer class you should override `pagination.BasePaginationSerializer` and set the fields that you want the serializer to return.
You can also override the name used for the object list field, by setting the `results_field` attribute, which defaults to `'results'`.
+## Example
+
For example, to nest a pair of links labelled 'prev' and 'next', and set the name for the results field to 'objects', you might use something like this.
class LinksSerializer(serializers.Serializer):
diff --git a/docs/api-guide/parsers.md b/docs/api-guide/parsers.md
index 0985b2ca..ac904720 100644
--- a/docs/api-guide/parsers.md
+++ b/docs/api-guide/parsers.md
@@ -8,7 +8,7 @@ sending more complex data than simple forms
>
> &mdash; Malcom Tredinnick, [Django developers group][cite]
-REST framework includes a number of built in Parser classes, that allow you to accept requests with various media types. There is also support for defining your own custom parsers, which gives you the flexiblity to design the media types that your API accepts.
+REST framework includes a number of built in Parser classes, that allow you to accept requests with various media types. There is also support for defining your own custom parsers, which gives you the flexibility to design the media types that your API accepts.
## How the parser is determined
@@ -16,10 +16,10 @@ The set of valid parsers for a view is always defined as a list of classes. Whe
## Setting the parsers
-The default set of parsers may be set globally, using the `DEFAULT_PARSERS` setting. For example, the following settings would allow requests with `YAML` content.
+The default set of parsers may be set globally, using the `DEFAULT_PARSER_CLASSES` setting. For example, the following settings would allow requests with `YAML` content.
REST_FRAMEWORK = {
- 'DEFAULT_PARSERS': (
+ 'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.YAMLParser',
)
}
@@ -65,7 +65,7 @@ Parses `YAML` request content.
Parses REST framework's default style of `XML` request content.
-Note that the `XML` markup language is used typically used as the base language for more strictly defined domain-specific languages, such as `RSS`, `Atom`, and `XHTML`.
+Note that the `XML` markup language is typically used as the base language for more strictly defined domain-specific languages, such as `RSS`, `Atom`, and `XHTML`.
If you are considering using `XML` for your API, you may want to consider implementing a custom renderer and parser for your specific requirements, and using an existing domain-specific media-type, or creating your own custom XML-based media-type.
diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md
index b25b52be..0b7b32e9 100644
--- a/docs/api-guide/permissions.md
+++ b/docs/api-guide/permissions.md
@@ -6,7 +6,7 @@
>
> &mdash; [Apple Developer Documentation][cite]
-Together with [authentication] and [throttling], permissions determine wheter a request should be granted or denied access.
+Together with [authentication] and [throttling], permissions determine whether a request should be granted or denied access.
Permission checks are always run at the very start of the view, before any other code is allowed to proceed. Permission checks will typically use the authentication information in the `request.user` and `request.auth` properties to determine if the incoming request should be permitted.
@@ -25,10 +25,10 @@ Object level permissions are run by REST framework's generic views when `.get_ob
## Setting the permission policy
-The default permission policy may be set globally, using the `DEFAULT_PERMISSIONS` setting. For example.
+The default permission policy may be set globally, using the `DEFAULT_PERMISSION_CLASSES` setting. For example.
REST_FRAMEWORK = {
- 'DEFAULT_PERMISSIONS': (
+ 'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}
diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md
index 24cca181..b6db376c 100644
--- a/docs/api-guide/renderers.md
+++ b/docs/api-guide/renderers.md
@@ -6,7 +6,7 @@
>
> &mdash; [Django documentation][cite]
-REST framework includes a number of built in Renderer classes, that allow you to return responses with various media types. There is also support for defining your own custom renderers, which gives you the flexiblity to design your own media types.
+REST framework includes a number of built in Renderer classes, that allow you to return responses with various media types. There is also support for defining your own custom renderers, which gives you the flexibility to design your own media types.
## How the renderer is determined
@@ -18,10 +18,10 @@ For more information see the documentation on [content negotation][conneg].
## Setting the renderers
-The default set of renderers may be set globally, using the `DEFAULT_RENDERERS` setting. For example, the following settings would use `YAML` as the main media type and also include the self describing API.
+The default set of renderers may be set globally, using the `DEFAULT_RENDERER_CLASSES` setting. For example, the following settings would use `YAML` as the main media type and also include the self describing API.
REST_FRAMEWORK = {
- 'DEFAULT_RENDERERS': (
+ 'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.YAMLRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
)
@@ -229,7 +229,7 @@ For example:
## Designing your media types
-For the purposes of many Web APIs, simple `JSON` responses with hyperlinked relations may be sufficient. If you want to fully embrace RESTful design and [HATEOAS] you'll neeed to consider the design and usage of your media types in more detail.
+For the purposes of many Web APIs, simple `JSON` responses with hyperlinked relations may be sufficient. If you want to fully embrace RESTful design and [HATEOAS] you'll need to consider the design and usage of your media types in more detail.
In [the words of Roy Fielding][quote], "A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state, or in defining extended relation names and/or hypertext-enabled mark-up for existing standard media types.".
diff --git a/docs/api-guide/requests.md b/docs/api-guide/requests.md
index 439c97bc..72932f5d 100644
--- a/docs/api-guide/requests.md
+++ b/docs/api-guide/requests.md
@@ -25,19 +25,19 @@ For more details see the [parsers documentation].
## .FILES
-`request.FILES` returns any uploaded files that may be present in the content of the request body. This is the same as the standard `HttpRequest` behavior, except that the same flexible request parsing that is used for `request.DATA`.
+`request.FILES` returns any uploaded files that may be present in the content of the request body. This is the same as the standard `HttpRequest` behavior, except that the same flexible request parsing is used for `request.DATA`.
For more details see the [parsers documentation].
## .QUERY_PARAMS
-`request.QUERY_PARAMS` is a more correcly named synonym for `request.GET`.
+`request.QUERY_PARAMS` is a more correctly named synonym for `request.GET`.
For clarity inside your code, we recommend using `request.QUERY_PARAMS` instead of the usual `request.GET`, as *any* HTTP method type may include query parameters.
## .parsers
-The `APIView` class or `@api_view` decorator will ensure that this property is automatically to a list of `Parser` instances, based on the `parser_classes` set on the view or based on the `DEFAULT_PARSERS` setting.
+The `APIView` class or `@api_view` decorator will ensure that this property is automatically set to a list of `Parser` instances, based on the `parser_classes` set on the view or based on the `DEFAULT_PARSER_CLASSES` setting.
You won't typically need to access this property.
@@ -51,7 +51,7 @@ If a client sends a request with a content-type that cannot be parsed then a `Un
# Authentication
-REST framework provides flexbile, per-request authentication, that gives you the abilty to:
+REST framework provides flexible, per-request authentication, that gives you the ability to:
* Use different authentication policies for different parts of your API.
* Support the use of multiple authentication policies.
@@ -75,7 +75,7 @@ For more details see the [authentication documentation].
## .authenticators
-The `APIView` class or `@api_view` decorator will ensure that this property is automatically to a list of `Authentication` instances, based on the `authentication_classes` set on the view or based on the `DEFAULT_AUTHENTICATORS` setting.
+The `APIView` class or `@api_view` decorator will ensure that this property is automatically set to a list of `Authentication` instances, based on the `authentication_classes` set on the view or based on the `DEFAULT_AUTHENTICATORS` setting.
You won't typically need to access this property.
@@ -83,7 +83,7 @@ You won't typically need to access this property.
# Browser enhancements
-REST framework supports a few browser enhancments such as browser-based `PUT` and `DELETE` forms.
+REST framework supports a few browser enhancements such as browser-based `PUT` and `DELETE` forms.
## .method
@@ -125,4 +125,4 @@ Note that due to implementation reasons the `Request` class does not inherit fro
[cite]: https://groups.google.com/d/topic/django-developers/dxI4qVzrBY4/discussion
[parsers documentation]: parsers.md
[authentication documentation]: authentication.md
-[browser enhancements documentation]: ../topics/browser-enhancements.md \ No newline at end of file
+[browser enhancements documentation]: ../topics/browser-enhancements.md
diff --git a/docs/api-guide/responses.md b/docs/api-guide/responses.md
index 395decda..794f9377 100644
--- a/docs/api-guide/responses.md
+++ b/docs/api-guide/responses.md
@@ -86,7 +86,7 @@ The `Response` class extends `SimpleTemplateResponse`, and all the usual attribu
**Signature:** `.render()`
-As with any other `TemplateResponse`, this methd is called to render the serialized data of the response into the final response content. When `.render()` is called, the response content will be set to the result of calling the `.render(data, accepted_media_type, renderer_context)` method on the `accepted_renderer` instance.
+As with any other `TemplateResponse`, this method is called to render the serialized data of the response into the final response content. When `.render()` is called, the response content will be set to the result of calling the `.render(data, accepted_media_type, renderer_context)` method on the `accepted_renderer` instance.
You won't typically need to call `.render()` yourself, as it's handled by Django's standard response cycle.
diff --git a/docs/api-guide/reverse.md b/docs/api-guide/reverse.md
index 12346eb4..19930dc3 100644
--- a/docs/api-guide/reverse.md
+++ b/docs/api-guide/reverse.md
@@ -6,7 +6,7 @@
>
> &mdash; Roy Fielding, [Architectural Styles and the Design of Network-based Software Architectures][cite]
-As a rule, it's probably better practice to return absolute URIs from you Web APIs, such as `http://example.com/foobar`, rather than returning relative URIs, such as `/foobar`.
+As a rule, it's probably better practice to return absolute URIs from your Web APIs, such as `http://example.com/foobar`, rather than returning relative URIs, such as `/foobar`.
The advantages of doing so are:
diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md
index 47958fe3..c10a3f44 100644
--- a/docs/api-guide/serializers.md
+++ b/docs/api-guide/serializers.md
@@ -175,7 +175,7 @@ You can add extra fields to a `ModelSerializer` or override the default fields b
class Meta:
model = Account
-Extra fields can corrospond to any property or callable on the model.
+Extra fields can correspond to any property or callable on the model.
## Relational fields
@@ -187,7 +187,7 @@ The `PrimaryKeyRelatedField` and `HyperlinkedRelatedField` fields provide altern
The `ModelSerializer` class can itself be used as a field, in order to serialize relationships using nested representations.
-The `RelatedField` class may be subclassed to create a custom represenation of a relationship. The subclass should override `.to_native()`, and optionally `.from_native()` if deserialization is supported.
+The `RelatedField` class may be subclassed to create a custom representation of a relationship. The subclass should override `.to_native()`, and optionally `.from_native()` if deserialization is supported.
All the relational fields may be used for any relationship or reverse relationship on a model.
diff --git a/docs/api-guide/settings.md b/docs/api-guide/settings.md
index 84acd797..21efc853 100644
--- a/docs/api-guide/settings.md
+++ b/docs/api-guide/settings.md
@@ -11,10 +11,10 @@ Configuration for REST framework is all namespaced inside a single Django settin
For example your project's `settings.py` file might include something like this:
REST_FRAMEWORK = {
- 'DEFAULT_RENDERERS': (
+ 'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.YAMLRenderer',
)
- 'DEFAULT_PARSERS': (
+ 'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.YAMLParser',
)
}
@@ -26,7 +26,7 @@ you should use the `api_settings` object. For example.
from rest_framework.settings import api_settings
- print api_settings.DEFAULT_AUTHENTICATION
+ print api_settings.DEFAULT_AUTHENTICATION_CLASSES
The `api_settings` object will check for any user-defined settings, and otherwise fallback to the default values. Any setting that uses string import paths to refer to a class will automatically import and return the referenced class, instead of the string literal.
@@ -34,7 +34,7 @@ The `api_settings` object will check for any user-defined settings, and otherwis
# API Reference
-## DEFAULT_RENDERERS
+## DEFAULT_RENDERER_CLASSES
A list or tuple of renderer classes, that determines the default set of renderers that may be used when returning a `Response` object.
@@ -46,7 +46,7 @@ Default:
'rest_framework.renderers.TemplateHTMLRenderer'
)
-## DEFAULT_PARSERS
+## DEFAULT_PARSER_CLASSES
A list or tuple of parser classes, that determines the default set of parsers used when accessing the `request.DATA` property.
@@ -57,7 +57,7 @@ Default:
'rest_framework.parsers.FormParser'
)
-## DEFAULT_AUTHENTICATION
+## DEFAULT_AUTHENTICATION_CLASSES
A list or tuple of authentication classes, that determines the default set of authenticators used when accessing the `request.user` or `request.auth` properties.
@@ -68,25 +68,25 @@ Default:
'rest_framework.authentication.UserBasicAuthentication'
)
-## DEFAULT_PERMISSIONS
+## DEFAULT_PERMISSION_CLASSES
A list or tuple of permission classes, that determines the default set of permissions checked at the start of a view.
Default: `()`
-## DEFAULT_THROTTLES
+## DEFAULT_THROTTLE_CLASSES
A list or tuple of throttle classes, that determines the default set of throttles checked at the start of a view.
Default: `()`
-## DEFAULT_MODEL_SERIALIZER
+## DEFAULT_MODEL_SERIALIZER_CLASS
**TODO**
Default: `rest_framework.serializers.ModelSerializer`
-## DEFAULT_PAGINATION_SERIALIZER
+## DEFAULT_PAGINATION_SERIALIZER_CLASS
**TODO**
diff --git a/docs/api-guide/throttling.md b/docs/api-guide/throttling.md
index 22e34187..d54433b1 100644
--- a/docs/api-guide/throttling.md
+++ b/docs/api-guide/throttling.md
@@ -27,10 +27,10 @@ If any throttle check fails an `exceptions.Throttled` exception will be raised,
## Setting the throttling policy
-The default throttling policy may be set globally, using the `DEFAULT_THROTTLES` and `DEFAULT_THROTTLE_RATES` settings. For example.
+The default throttling policy may be set globally, using the `DEFAULT_THROTTLE_CLASSES` and `DEFAULT_THROTTLE_RATES` settings. For example.
REST_FRAMEWORK = {
- 'DEFAULT_THROTTLES': (
+ 'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttles.AnonThrottle',
'rest_framework.throttles.UserThrottle',
)
@@ -80,7 +80,7 @@ The allowed request rate is determined from one of the following (in order of pr
## UserRateThrottle
-The `UserThrottle` will throttle users to a given rate of requests across the API. The user id is used to generate a unique key to throttle against. Unauthenticted requests will fall back to using the IP address of the incoming request to generate a unique key to throttle against.
+The `UserThrottle` will throttle users to a given rate of requests across the API. The user id is used to generate a unique key to throttle against. Unauthenticated requests will fall back to using the IP address of the incoming request to generate a unique key to throttle against.
The allowed request rate is determined from one of the following (in order of preference).
@@ -100,7 +100,7 @@ For example, multiple user throttle rates could be implemented by using the foll
...and the following settings.
REST_FRAMEWORK = {
- 'DEFAULT_THROTTLES': (
+ 'DEFAULT_THROTTLE_CLASSES': (
'example.throttles.BurstRateThrottle',
'example.throttles.SustainedRateThrottle',
)
@@ -114,7 +114,7 @@ For example, multiple user throttle rates could be implemented by using the foll
## ScopedRateThrottle
-The `ScopedThrottle` class can be used to restrict access to specific parts of the API. This throttle will only be applied if the view that is being accessed includes a `.throttle_scope` property. The unique throttle key will then be formed by concatenating the "scope" of the request with the unqiue user id or IP address.
+The `ScopedThrottle` class can be used to restrict access to specific parts of the API. This throttle will only be applied if the view that is being accessed includes a `.throttle_scope` property. The unique throttle key will then be formed by concatenating the "scope" of the request with the unique user id or IP address.
The allowed request rate is determined by the `DEFAULT_THROTTLE_RATES` setting using a key from the request "scope".
@@ -135,7 +135,7 @@ For example, given the following views...
...and the following settings.
REST_FRAMEWORK = {
- 'DEFAULT_THROTTLES': (
+ 'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttles.ScopedRateThrottle',
)
'DEFAULT_THROTTLE_RATES': {
@@ -152,6 +152,6 @@ User requests to either `ContactListView` or `ContactDetailView` would be restri
To create a custom throttle, override `BaseThrottle` and implement `.allow_request(request, view)`. The method should return `True` if the request should be allowed, and `False` otherwise.
-Optionally you may also override the `.wait()` method. If implemented, `.wait()` should return a recomended number of seconds to wait before attempting the next request, or `None`. The `.wait()` method will only be called if `.allow_request()` has previously returned `False`.
+Optionally you may also override the `.wait()` method. If implemented, `.wait()` should return a recommended number of seconds to wait before attempting the next request, or `None`. The `.wait()` method will only be called if `.allow_request()` has previously returned `False`.
[permissions]: permissions.md
diff --git a/docs/api-guide/views.md b/docs/api-guide/views.md
index 77349252..e3fbadb2 100644
--- a/docs/api-guide/views.md
+++ b/docs/api-guide/views.md
@@ -27,7 +27,7 @@ For example:
* Only admin users are able to access this view.
"""
authentication_classes = (authentication.TokenAuthentication,)
- permission_classes = (permissions.IsAdmin,)
+ permission_classes = (permissions.IsAdminUser,)
def get(self, request, format=None):
"""
@@ -123,4 +123,4 @@ REST framework also gives you to work with regular function based views...
**[TODO]**
[cite]: http://reinout.vanrees.org/weblog/2011/08/24/class-based-views-usage.html
-[cite2]: http://www.boredomandlaziness.org/2012/05/djangos-cbvs-are-not-mistake-but.html \ No newline at end of file
+[cite2]: http://www.boredomandlaziness.org/2012/05/djangos-cbvs-are-not-mistake-but.html
diff --git a/docs/css/default.css b/docs/css/default.css
index c1d2e885..57446ff9 100644
--- a/docs/css/default.css
+++ b/docs/css/default.css
@@ -88,6 +88,10 @@ pre {
font-weight: bold;
}
+.nav-list a {
+ overflow: hidden;
+}
+
/* Set the table of contents to static so it flows back into the content when
viewed on tablets and smaller. */
@media (max-width: 767px) {
diff --git a/docs/index.md b/docs/index.md
index 02bda081..f66ba7f4 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -47,7 +47,7 @@ Add `rest_framework` to your `INSTALLED_APPS`.
'rest_framework',
)
-If you're intending to use the browserable 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 want to add REST framework's login and logout views. Add the following to your root `urls.py` file.
urlpatterns = patterns('',
...
@@ -195,4 +195,4 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[group]: https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework
[DabApps]: http://dabapps.com
-[email]: mailto:tom@tomchristie.com \ No newline at end of file
+[email]: mailto:tom@tomchristie.com
diff --git a/docs/topics/csrf.md b/docs/topics/csrf.md
index a2ee1b9c..043144c1 100644
--- a/docs/topics/csrf.md
+++ b/docs/topics/csrf.md
@@ -5,8 +5,8 @@
> &mdash; [Jeff Atwood][cite]
* Explain need to add CSRF token to AJAX requests.
-* Explain defered CSRF style used by REST framework
+* Explain deferred CSRF style used by REST framework
* Why you should use Django's standard login/logout views, and not REST framework view
-[cite]: http://www.codinghorror.com/blog/2008/10/preventing-csrf-and-xsrf-attacks.html \ No newline at end of file
+[cite]: http://www.codinghorror.com/blog/2008/10/preventing-csrf-and-xsrf-attacks.html
diff --git a/docs/topics/rest-hypermedia-hateoas.md b/docs/topics/rest-hypermedia-hateoas.md
index 8b0309b9..d7646892 100644
--- a/docs/topics/rest-hypermedia-hateoas.md
+++ b/docs/topics/rest-hypermedia-hateoas.md
@@ -4,7 +4,7 @@
>
> &mdash; Mike Amundsen, [REST fest 2012 keynote][cite].
-First off, the disclaimer. The name "Django REST framework" was choosen simply to sure the project would be easily found by developers. Throughout the documentation we try to use the more simple and technically correct terminology of "Web APIs".
+First off, the disclaimer. The name "Django REST framework" was chosen simply to sure the project would be easily found by developers. Throughout the documentation we try to use the more simple and technically correct terminology of "Web APIs".
If you are serious about designing a Hypermedia APIs, you should look to resources outside of this documentation to help inform your design choices.
@@ -22,7 +22,7 @@ For a more thorough background, check out Klabnik's [Hypermedia API reading list
## Building Hypermedia APIs with REST framework
-REST framework is an agnositic Web API toolkit. It does help guide you towards building well-connected APIs, and makes it easy to design appropriate media types, but it does not strictly enforce any particular design style.
+REST framework is an agnostic Web API toolkit. It does help guide you towards building well-connected APIs, and makes it easy to design appropriate media types, but it does not strictly enforce any particular design style.
## What REST framework provides.
@@ -50,4 +50,4 @@ What REST framework doesn't do is give you is machine readable hypermedia format
[parser]: ../api-guide/parsers.md
[renderer]: ../api-guide/renderers.md
[fields]: ../api-guide/fields.md
-[conneg]: ../api-guide/content-negotiation.md \ No newline at end of file
+[conneg]: ../api-guide/content-negotiation.md
diff --git a/docs/tutorial/2-requests-and-responses.md b/docs/tutorial/2-requests-and-responses.md
index 7c8fc044..fc37322a 100644
--- a/docs/tutorial/2-requests-and-responses.md
+++ b/docs/tutorial/2-requests-and-responses.md
@@ -5,7 +5,7 @@ Let's introduce a couple of essential building blocks.
## Request objects
-REST framework intoduces a `Request` object that extends the regular `HttpRequest`, and provides more flexible request parsing. The core functionality of the `Request` object is the `request.DATA` attribute, which is similar to `request.POST`, but more useful for working with Web APIs.
+REST framework introduces a `Request` object that extends the regular `HttpRequest`, and provides more flexible request parsing. The core functionality of the `Request` object is the `request.DATA` attribute, which is similar to `request.POST`, but more useful for working with Web APIs.
request.POST # Only handles form data. Only works for 'POST' method.
request.DATA # Handles arbitrary data. Works any HTTP request with content.
diff --git a/docs/tutorial/3-class-based-views.md b/docs/tutorial/3-class-based-views.md
index 2f273364..0ee81ea3 100644
--- a/docs/tutorial/3-class-based-views.md
+++ b/docs/tutorial/3-class-based-views.md
@@ -107,7 +107,7 @@ Let's take a look at how we can compose our views by using the mixin classes.
We'll take a moment to examine exactly what's happening here - We're building our view using `MultipleObjectBaseView`, 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 explictly binding the `get` and `post` methods to the appropriate actions. Simple enough stuff so far.
+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 CommentInstance(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
diff --git a/docs/tutorial/6-resource-orientated-projects.md b/docs/tutorial/6-resource-orientated-projects.md
index e7190a77..9ee599ae 100644
--- a/docs/tutorial/6-resource-orientated-projects.md
+++ b/docs/tutorial/6-resource-orientated-projects.md
@@ -5,7 +5,7 @@ Resource classes are just View classes that don't have any handler methods bound
This allows us to:
* Encapsulate common behaviour across a class of views, in a single Resource class.
-* Separate out the actions of a Resource from the specfics of how those actions should be bound to a particular set of URLs.
+* Separate out the actions of a Resource from the specifics of how those actions should be bound to a particular set of URLs.
## Refactoring to use Resources, not Views
diff --git a/docs/tutorial/quickstart.md b/docs/tutorial/quickstart.md
index 851db3c7..6bde725b 100644
--- a/docs/tutorial/quickstart.md
+++ b/docs/tutorial/quickstart.md
@@ -126,7 +126,7 @@ We'd also like to set a few global settings. We'd like to turn on pagination, a
)
REST_FRAMEWORK = {
- 'DEFAULT_PERMISSIONS': ('rest_framework.permissions.IsAdminUser',),
+ 'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAdminUser',),
'PAGINATE_BY': 10
}
@@ -169,4 +169,4 @@ If you want to get a more in depth understanding of how REST framework fits toge
[image]: ../img/quickstart.png
[tutorial]: 1-serialization.md
-[guide]: ../#api-guide \ No newline at end of file
+[guide]: ../#api-guide
diff --git a/rest_framework/fields.py b/rest_framework/fields.py
index 29940946..f610d6aa 100644
--- a/rest_framework/fields.py
+++ b/rest_framework/fields.py
@@ -71,6 +71,8 @@ class Field(object):
value = obj
for component in self.source.split('.'):
value = getattr(value, component)
+ if is_simple_callable(value):
+ value = value()
else:
value = getattr(obj, field_name)
return self.to_native(value)
@@ -238,6 +240,9 @@ class RelatedField(WritableField):
return self.to_native(value)
def field_from_native(self, data, field_name, into):
+ if self.readonly:
+ return
+
value = data.get(field_name)
into[(self.source or field_name) + '_id'] = self.from_native(value)
diff --git a/rest_framework/generics.py b/rest_framework/generics.py
index 59739d01..18c1033d 100644
--- a/rest_framework/generics.py
+++ b/rest_framework/generics.py
@@ -15,7 +15,7 @@ class BaseView(views.APIView):
Base class for all other generic views.
"""
serializer_class = None
- model_serializer_class = api_settings.MODEL_SERIALIZER
+ model_serializer_class = api_settings.DEFAULT_MODEL_SERIALIZER_CLASS
def get_serializer_context(self):
"""
@@ -56,7 +56,7 @@ class MultipleObjectBaseView(MultipleObjectMixin, BaseView):
Base class for generic views onto a queryset.
"""
- pagination_serializer_class = api_settings.PAGINATION_SERIALIZER
+ pagination_serializer_class = api_settings.DEFAULT_PAGINATION_SERIALIZER_CLASS
paginate_by = api_settings.PAGINATE_BY
def get_pagination_serializer_class(self):
diff --git a/rest_framework/request.py b/rest_framework/request.py
index b212680f..5870be82 100644
--- a/rest_framework/request.py
+++ b/rest_framework/request.py
@@ -92,7 +92,7 @@ class Request(object):
self.parser_context['request'] = self
def _default_negotiator(self):
- return api_settings.DEFAULT_CONTENT_NEGOTIATION()
+ return api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS()
@property
def method(self):
diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py
index 6724bbdf..221cbf2f 100644
--- a/rest_framework/serializers.py
+++ b/rest_framework/serializers.py
@@ -247,6 +247,19 @@ class BaseSerializer(Field):
if not self._errors:
return self.restore_object(attrs, instance=getattr(self, 'object', None))
+ def field_to_native(self, obj, field_name):
+ """
+ Override default so that we can apply ModelSerializer as a nested
+ field to relationships.
+ """
+ obj = getattr(obj, self.source or field_name)
+
+ # If the object has an "all" method, assume it's a relationship
+ if is_simple_callable(getattr(obj, 'all', None)):
+ return [self.to_native(item) for item in obj.all()]
+
+ return self.to_native(obj)
+
@property
def errors(self):
"""
@@ -295,16 +308,6 @@ class ModelSerializer(Serializer):
"""
_options_class = ModelSerializerOptions
- def field_to_native(self, obj, field_name):
- """
- Override default so that we can apply ModelSerializer as a nested
- field to relationships.
- """
- obj = getattr(obj, self.source or field_name)
- if obj.__class__.__name__ in ('RelatedManager', 'ManyRelatedManager'):
- return [self.to_native(item) for item in obj.all()]
- return self.to_native(obj)
-
def default_fields(self, serialize, obj=None, data=None, nested=False):
"""
Return all the fields that should be serialized for the model.
diff --git a/rest_framework/settings.py b/rest_framework/settings.py
index 8bbb2f75..3c508294 100644
--- a/rest_framework/settings.py
+++ b/rest_framework/settings.py
@@ -3,11 +3,11 @@ Settings for REST framework are all namespaced in the REST_FRAMEWORK setting.
For example your project's `settings.py` file might look like this:
REST_FRAMEWORK = {
- 'DEFAULT_RENDERERS': (
+ 'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.YAMLRenderer',
)
- 'DEFAULT_PARSERS': (
+ 'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.YAMLParser',
)
@@ -24,30 +24,33 @@ from django.utils import importlib
USER_SETTINGS = getattr(settings, 'REST_FRAMEWORK', None)
DEFAULTS = {
- 'DEFAULT_RENDERERS': (
+ 'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
),
- 'DEFAULT_PARSERS': (
+ 'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser'
),
- 'DEFAULT_AUTHENTICATION': (
+ 'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication'
),
- 'DEFAULT_PERMISSIONS': (),
- 'DEFAULT_THROTTLES': (),
- 'DEFAULT_CONTENT_NEGOTIATION':
+ 'DEFAULT_PERMISSION_CLASSES': (),
+ 'DEFAULT_THROTTLE_CLASSES': (),
+ 'DEFAULT_CONTENT_NEGOTIATION_CLASS':
'rest_framework.negotiation.DefaultContentNegotiation',
+
+ 'DEFAULT_MODEL_SERIALIZER_CLASS':
+ 'rest_framework.serializers.ModelSerializer',
+ 'DEFAULT_PAGINATION_SERIALIZER_CLASS':
+ 'rest_framework.pagination.PaginationSerializer',
+
'DEFAULT_THROTTLE_RATES': {
'user': None,
'anon': None,
},
-
- 'MODEL_SERIALIZER': 'rest_framework.serializers.ModelSerializer',
- 'PAGINATION_SERIALIZER': 'rest_framework.pagination.PaginationSerializer',
'PAGINATE_BY': None,
'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser',
@@ -65,14 +68,14 @@ DEFAULTS = {
# List of settings that may be in string import notation.
IMPORT_STRINGS = (
- 'DEFAULT_RENDERERS',
- 'DEFAULT_PARSERS',
- 'DEFAULT_AUTHENTICATION',
- 'DEFAULT_PERMISSIONS',
- 'DEFAULT_THROTTLES',
- 'DEFAULT_CONTENT_NEGOTIATION',
- 'MODEL_SERIALIZER',
- 'PAGINATION_SERIALIZER',
+ 'DEFAULT_RENDERER_CLASSES',
+ 'DEFAULT_PARSER_CLASSES',
+ 'DEFAULT_AUTHENTICATION_CLASSES',
+ 'DEFAULT_PERMISSION_CLASSES',
+ 'DEFAULT_THROTTLE_CLASSES',
+ 'DEFAULT_CONTENT_NEGOTIATION_CLASS',
+ 'DEFAULT_MODEL_SERIALIZER_CLASS',
+ 'DEFAULT_PAGINATION_SERIALIZER_CLASS',
'UNAUTHENTICATED_USER',
'UNAUTHENTICATED_TOKEN',
)
@@ -111,7 +114,7 @@ class APISettings(object):
For example:
from rest_framework.settings import api_settings
- print api_settings.DEFAULT_RENDERERS
+ print api_settings.DEFAULT_RENDERER_CLASSES
Any setting with string import paths will be automatically resolved
and return the class, rather than the string literal.
diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py
index 75dab2f7..8e721737 100644
--- a/rest_framework/tests/models.py
+++ b/rest_framework/tests/models.py
@@ -92,6 +92,17 @@ class Comment(RESTFrameworkModel):
content = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
+
class ActionItem(RESTFrameworkModel):
title = models.CharField(max_length=200)
done = models.BooleanField(default=False)
+
+
+# Models for reverse relations
+class BlogPost(RESTFrameworkModel):
+ title = models.CharField(max_length=100)
+
+
+class BlogPostComment(RESTFrameworkModel):
+ text = models.TextField()
+ blog_post = models.ForeignKey(BlogPost)
diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py
index 610ed85f..2dfc04e1 100644
--- a/rest_framework/tests/serializer.py
+++ b/rest_framework/tests/serializer.py
@@ -4,6 +4,11 @@ from rest_framework import serializers
from rest_framework.tests.models import *
+class SubComment(object):
+ def __init__(self, sub_comment):
+ self.sub_comment = sub_comment
+
+
class Comment(object):
def __init__(self, email, content, created):
self.email = email
@@ -13,13 +18,18 @@ class Comment(object):
def __eq__(self, other):
return all([getattr(self, attr) == getattr(other, attr)
for attr in ('email', 'content', 'created')])
+
+ def get_sub_comment(self):
+ sub_comment = SubComment('And Merry Christmas!')
+ return sub_comment
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=1000)
created = serializers.DateTimeField()
-
+ sub_comment = serializers.Field(source='get_sub_comment.sub_comment')
+
def restore_object(self, data, instance=None):
if instance is None:
return Comment(**data)
@@ -42,7 +52,14 @@ class BasicTests(TestCase):
self.data = {
'email': 'tom@example.com',
'content': 'Happy new year!',
- 'created': datetime.datetime(2012, 1, 1)
+ 'created': datetime.datetime(2012, 1, 1),
+ 'sub_comment': 'This wont change'
+ }
+ self.expected = {
+ 'email': 'tom@example.com',
+ 'content': 'Happy new year!',
+ 'created': datetime.datetime(2012, 1, 1),
+ 'sub_comment': 'And Merry Christmas!'
}
def test_empty(self):
@@ -50,14 +67,14 @@ class BasicTests(TestCase):
expected = {
'email': '',
'content': '',
- 'created': None
+ 'created': None,
+ 'sub_comment': ''
}
self.assertEquals(serializer.data, expected)
def test_retrieve(self):
- serializer = CommentSerializer(instance=self.comment)
- expected = self.data
- self.assertEquals(serializer.data, expected)
+ serializer = CommentSerializer(instance=self.comment)
+ self.assertEquals(serializer.data, self.expected)
def test_create(self):
serializer = CommentSerializer(self.data)
@@ -65,6 +82,7 @@ class BasicTests(TestCase):
self.assertEquals(serializer.is_valid(), True)
self.assertEquals(serializer.object, expected)
self.assertFalse(serializer.object is expected)
+ self.assertEquals(serializer.data['sub_comment'], 'And Merry Christmas!')
def test_update(self):
serializer = CommentSerializer(self.data, instance=self.comment)
@@ -72,6 +90,7 @@ class BasicTests(TestCase):
self.assertEquals(serializer.is_valid(), True)
self.assertEquals(serializer.object, expected)
self.assertTrue(serializer.object is expected)
+ self.assertEquals(serializer.data['sub_comment'], 'And Merry Christmas!')
class ValidationTests(TestCase):
@@ -283,3 +302,32 @@ class CallableDefaultValueTests(TestCase):
self.assertEquals(len(self.objects.all()), 1)
self.assertEquals(instance.pk, 1)
self.assertEquals(instance.text, 'overridden')
+
+
+class ManyRelatedTests(TestCase):
+ def setUp(self):
+
+ class BlogPostCommentSerializer(serializers.Serializer):
+ text = serializers.CharField()
+
+ class BlogPostSerializer(serializers.Serializer):
+ title = serializers.CharField()
+ comments = BlogPostCommentSerializer(source='blogpostcomment_set')
+
+ self.serializer_class = BlogPostSerializer
+
+ def test_reverse_relations(self):
+ post = BlogPost.objects.create(title="Test blog post")
+ post.blogpostcomment_set.create(text="I hate this blog post")
+ post.blogpostcomment_set.create(text="I love this blog post")
+
+ serializer = self.serializer_class(instance=post)
+ expected = {
+ 'title': 'Test blog post',
+ 'comments': [
+ {'text': 'I hate this blog post'},
+ {'text': 'I love this blog post'}
+ ]
+ }
+
+ self.assertEqual(serializer.data, expected)
diff --git a/rest_framework/throttling.py b/rest_framework/throttling.py
index 6e7a0b72..6860e6b9 100644
--- a/rest_framework/throttling.py
+++ b/rest_framework/throttling.py
@@ -60,7 +60,7 @@ class SimpleRateThrottle(BaseThrottle):
Determine the string representation of the allowed request rate.
"""
if not getattr(self, 'scope', None):
- msg = ("You must set either `.scope` or `.rate` for '%s' thottle" %
+ msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
self.__class__.__name__)
raise exceptions.ConfigurationError(msg)
@@ -137,7 +137,7 @@ class AnonRateThrottle(SimpleRateThrottle):
"""
Limits the rate of API calls that may be made by a anonymous users.
- The IP address of the request will be used as the unqiue cache key.
+ The IP address of the request will be used as the unique cache key.
"""
scope = 'anon'
diff --git a/rest_framework/urlpatterns.py b/rest_framework/urlpatterns.py
index 386c78a2..316ccd19 100644
--- a/rest_framework/urlpatterns.py
+++ b/rest_framework/urlpatterns.py
@@ -2,26 +2,23 @@ from django.conf.urls.defaults import url
from rest_framework.settings import api_settings
-def format_suffix_patterns(urlpatterns, suffix_required=False,
- suffix_kwarg=None, allowed=None):
+def format_suffix_patterns(urlpatterns, suffix_required=False, allowed=None):
"""
Supplement existing urlpatterns with corrosponding patterns that also
include a '.format' suffix. Retains urlpattern ordering.
+ urlpatterns:
+ A list of URL patterns.
+
suffix_required:
If `True`, only suffixed URLs will be generated, and non-suffixed
URLs will not be used. Defaults to `False`.
- suffix_kwarg:
- The name of the kwarg that will be passed to the view.
- Defaults to 'format'.
-
allowed:
An optional tuple/list of allowed suffixes. eg ['json', 'api']
Defaults to `None`, which allows any suffix.
-
"""
- suffix_kwarg = suffix_kwarg or api_settings.FORMAT_SUFFIX_KWARG
+ suffix_kwarg = api_settings.FORMAT_SUFFIX_KWARG
if allowed:
if len(allowed) == 1:
allowed_pattern = allowed[0]
diff --git a/rest_framework/views.py b/rest_framework/views.py
index 357d8939..c721be3c 100644
--- a/rest_framework/views.py
+++ b/rest_framework/views.py
@@ -54,12 +54,12 @@ def _camelcase_to_spaces(content):
class APIView(View):
settings = api_settings
- renderer_classes = api_settings.DEFAULT_RENDERERS
- parser_classes = api_settings.DEFAULT_PARSERS
- authentication_classes = api_settings.DEFAULT_AUTHENTICATION
- throttle_classes = api_settings.DEFAULT_THROTTLES
- permission_classes = api_settings.DEFAULT_PERMISSIONS
- content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION
+ renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
+ parser_classes = api_settings.DEFAULT_PARSER_CLASSES
+ authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
+ throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
+ permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
+ content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
@classmethod
def as_view(cls, **initkwargs):