Skip to content

Commit b106ebd

Browse files
committed
Merge pull request #1800 from tomchristie/version-3.0
Version 3.0
2 parents 650a91a + 8861a7d commit b106ebd

File tree

125 files changed

+11324
-9004
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

125 files changed

+11324
-9004
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ You can also use the excellent [`tox`][tox] testing tool to run the tests agains
7575

7676
It's a good idea to make pull requests early on. A pull request represents the start of a discussion, and doesn't necessarily need to be the final, finished submission.
7777

78-
It's also always best to make a new branch before starting work on a pull request. This means that you'll be able to later switch back to working on another seperate issue without interfering with an ongoing pull requests.
78+
It's also always best to make a new branch before starting work on a pull request. This means that you'll be able to later switch back to working on another separate issue without interfering with an ongoing pull requests.
7979

8080
It's also useful to remember that if you have an outstanding pull request then pushing new commits to your GitHub repo will also automatically update the pull requests.
8181

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ There is a live example API for testing purposes, [available here][sandbox].
2727
# Requirements
2828

2929
* Python (2.6.5+, 2.7, 3.2, 3.3, 3.4)
30-
* Django (1.4.2+, 1.5, 1.6, 1.7)
30+
* Django (1.4.11+, 1.5.5+, 1.6, 1.7)
3131

3232
# Installation
3333

docs/api-guide/fields.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,27 @@ Corresponds to `django.db.models.fields.FloatField`.
274274

275275
## DecimalField
276276

277-
A decimal representation.
277+
A decimal representation, represented in Python by a Decimal instance.
278+
279+
Has two required arguments:
280+
281+
- `max_digits` The maximum number of digits allowed in the number. Note that this number must be greater than or equal to decimal_places.
282+
283+
- `decimal_places` The number of decimal places to store with the number.
284+
285+
For example, to validate numbers up to 999 with a resolution of 2 decimal places, you would use:
286+
287+
serializers.DecimalField(max_digits=5, decimal_places=2)
288+
289+
And to validate numbers up to anything less than one billion with a resolution of 10 decimal places:
290+
291+
serializers.DecimalField(max_digits=19, decimal_places=10)
292+
293+
This field also takes an optional argument, `coerce_to_string`. If set to `True` the representation will be output as a string. If set to `False` the representation will be left as a `Decimal` instance and the final representation will be determined by the renderer.
294+
295+
If unset, this will default to the same value as the `COERCE_DECIMAL_TO_STRING` setting, which is `True` unless set otherwise.
296+
297+
**Signature:** `DecimalField(max_digits, decimal_places, coerce_to_string=None)`
278298

279299
Corresponds to `django.db.models.fields.DecimalField`.
280300

docs/api-guide/generic-views.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ Typically when using the generic views, you'll override the view, and set severa
1919

2020
from django.contrib.auth.models import User
2121
from myapp.serializers import UserSerializer
22-
from rest_framework import generics
23-
from rest_framework.permissions import IsAdminUser
22+
from rest_framework import generics
23+
from rest_framework.permissions import IsAdminUser
2424

2525
class UserList(generics.ListCreateAPIView):
2626
queryset = User.objects.all()
@@ -212,8 +212,6 @@ Provides a `.list(request, *args, **kwargs)` method, that implements listing a q
212212

213213
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.
214214

215-
If the queryset is empty this returns a `200 OK` response, unless the `.allow_empty` attribute on the view is set to `False`, in which case it will return a `404 Not Found`.
216-
217215
## CreateModelMixin
218216

219217
Provides a `.create(request, *args, **kwargs)` method, that implements creating and saving a new model instance.
@@ -370,6 +368,20 @@ If you are using a mixin across multiple views, you can take this a step further
370368

371369
Using custom base classes is a good option if you have custom behavior that consistently needs to be repeated across a large number of views throughout your project.
372370

371+
---
372+
373+
# PUT as create
374+
375+
Prior to version 3.0 the REST framework mixins treated `PUT` as either an update or a create operation, depending on if the object already existed or not.
376+
377+
Allowing `PUT` as create operations is problematic, as it necessarily exposes information about the existence or non-existance of objects. It's also not obvious that transparently allowing re-creating of previously deleted instances is necessarily a better default behavior than simply returning `404` responses.
378+
379+
Both styles "`PUT` as 404" and "`PUT` as create" can be valid in different circumstances, but from version 3.0 onwards we now use 404 behavior as the default, due to it being simpler and more obvious.
380+
381+
If you need to generic PUT-as-create behavior you may want to include something like [this `AllowPUTAsCreateMixin` class](https://gist.github.com/tomchristie/a2ace4577eff2c603b1b) as a mixin to your views.
382+
383+
---
384+
373385
# Third party packages
374386

375387
The following third party packages provide additional generic view implementations.

docs/api-guide/metadata.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<a class="github" href="metadata.py"></a>
2+
3+
# Metadata
4+
5+
> [The `OPTIONS`] method allows a client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval.
6+
>
7+
> &mdash; [RFC7231, Section 4.3.7.][cite]
8+
9+
REST framework includes a configurable mechanism for determining how your API should respond to `OPTIONS` requests. This allows you to return API schema or other resource information.
10+
11+
There are not currently any widely adopted conventions for exactly what style of response should be returned for HTTP `OPTIONS` requests, so we provide an ad-hoc style that returns some useful information.
12+
13+
Here's an example response that demonstrates the information that is returned by default.
14+
15+
HTTP 200 OK
16+
Allow: GET, POST, HEAD, OPTIONS
17+
Content-Type: application/json
18+
19+
{
20+
"name": "To Do List",
21+
"description": "List existing 'To Do' items, or create a new item.",
22+
"renders": [
23+
"application/json",
24+
"text/html"
25+
],
26+
"parses": [
27+
"application/json",
28+
"application/x-www-form-urlencoded",
29+
"multipart/form-data"
30+
],
31+
"actions": {
32+
"POST": {
33+
"note": {
34+
"type": "string",
35+
"required": false,
36+
"read_only": false,
37+
"label": "title",
38+
"max_length": 100
39+
}
40+
}
41+
}
42+
}
43+
44+
## Setting the metadata scheme
45+
46+
You can set the metadata class globally using the `'DEFAULT_METADATA_CLASS'` settings key:
47+
48+
REST_FRAMEWORK = {
49+
'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata'
50+
}
51+
52+
Or you can set the metadata class individually for a view:
53+
54+
class APIRoot(APIView):
55+
metadata_class = APIRootMetadata
56+
57+
def get(self, request, format=None):
58+
return Response({
59+
...
60+
})
61+
62+
The REST framework package only includes a single metadata class implementation, named `SimpleMetadata`. If you want to use an alternative style you'll need to implement a custom metadata class.
63+
64+
## Creating schema endpoints
65+
66+
If you have specific requirements for creating schema endpoints that are accessed with regular `GET` requests, you might consider re-using the metadata API for doing so.
67+
68+
For example, the following additional route could be used on a viewset to provide a linkable schema endpoint.
69+
70+
@list_route(methods=['GET'])
71+
def schema(self, request):
72+
meta = self.metadata_class()
73+
data = meta.determine_metadata(request, self)
74+
return Response(data)
75+
76+
There are a couple of reasons that you might choose to take this approach, including that `OPTIONS` responses [are not cacheable][no-options].
77+
78+
---
79+
80+
# Custom metadata classes
81+
82+
If you want to provide a custom metadata class you should override `BaseMetadata` and implement the `determine_metadata(self, request, view)` method.
83+
84+
Useful things that you might want to do could include returning schema information, using a format such as [JSON schema][json-schema], or returning debug information to admin users.
85+
86+
## Example
87+
88+
The following class could be used to limit the information that is returned to `OPTIONS` requests.
89+
90+
class MinimalMetadata(BaseMetadata):
91+
"""
92+
Don't include field and other information for `OPTIONS` requests.
93+
Just return the name and description.
94+
"""
95+
def determine_metadata(self, request, view):
96+
return {
97+
'name': view.get_view_name(),
98+
'description': view.get_view_description()
99+
}
100+
101+
[cite]: http://tools.ietf.org/html/rfc7231#section-4.3.7
102+
[no-options]: https://www.mnot.net/blog/2012/10/29/NO_OPTIONS
103+
[json-schema]: http://json-schema.org/

docs/api-guide/renderers.md

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -74,37 +74,18 @@ If your API includes views that can serve both regular webpages and API response
7474

7575
Renders the request data into `JSON`, using utf-8 encoding.
7676

77-
Note that non-ascii characters will be rendered using JSON's `\uXXXX` character escape. For example:
77+
Note that the default style is to include unicode characters, and render the response using a compact style with no unnecessary whitespace:
7878

79-
{"unicode black star": "\u2605"}
79+
{"unicode black star":"★","value":999}
8080

8181
The client may additionally include an `'indent'` media type parameter, in which case the returned `JSON` will be indented. For example `Accept: application/json; indent=4`.
8282

8383
{
84-
"unicode black star": "\u2605"
84+
"unicode black star": "★",
85+
"value": 999
8586
}
8687

87-
**.media_type**: `application/json`
88-
89-
**.format**: `'.json'`
90-
91-
**.charset**: `None`
92-
93-
## UnicodeJSONRenderer
94-
95-
Renders the request data into `JSON`, using utf-8 encoding.
96-
97-
Note that non-ascii characters will not be character escaped. For example:
98-
99-
{"unicode black star": "★"}
100-
101-
The client may additionally include an `'indent'` media type parameter, in which case the returned `JSON` will be indented. For example `Accept: application/json; indent=4`.
102-
103-
{
104-
"unicode black star": "★"
105-
}
106-
107-
Both the `JSONRenderer` and `UnicodeJSONRenderer` styles conform to [RFC 4627][rfc4627], and are syntactically valid JSON.
88+
The default JSON encoding style can be altered using the `UNICODE_JSON` and `COMPACT_JSON` settings keys.
10889

10990
**.media_type**: `application/json`
11091

docs/api-guide/settings.md

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ A format string that should be used by default for rendering the output of `Date
265265

266266
May be any of `None`, `'iso-8601'` or a Python [strftime format][strftime] string.
267267

268-
Default: `None`
268+
Default: `'iso-8601'`
269269

270270
#### DATETIME_INPUT_FORMATS
271271

@@ -281,7 +281,7 @@ A format string that should be used by default for rendering the output of `Date
281281

282282
May be any of `None`, `'iso-8601'` or a Python [strftime format][strftime] string.
283283

284-
Default: `None`
284+
Default: `'iso-8601'`
285285

286286
#### DATE_INPUT_FORMATS
287287

@@ -297,7 +297,7 @@ A format string that should be used by default for rendering the output of `Time
297297

298298
May be any of `None`, `'iso-8601'` or a Python [strftime format][strftime] string.
299299

300-
Default: `None`
300+
Default: `'iso-8601'`
301301

302302
#### TIME_INPUT_FORMATS
303303

@@ -309,6 +309,46 @@ Default: `['iso-8601']`
309309

310310
---
311311

312+
## Encodings
313+
314+
#### UNICODE_JSON
315+
316+
When set to `True`, JSON responses will allow unicode characters in responses. For example:
317+
318+
{"unicode black star":"★"}
319+
320+
When set to `False`, JSON responses will escape non-ascii characters, like so:
321+
322+
{"unicode black star":"\u2605"}
323+
324+
Both styles conform to [RFC 4627][rfc4627], and are syntactically valid JSON. The unicode style is prefered as being more user-friendly when inspecting API responses.
325+
326+
Default: `True`
327+
328+
#### COMPACT_JSON
329+
330+
When set to `True`, JSON responses will return compact representations, with no spacing after `':'` and `','` characters. For example:
331+
332+
{"is_admin":false,"email":"jane@example"}
333+
334+
When set to `False`, JSON responses will return slightly more verbose representations, like so:
335+
336+
{"is_admin": false, "email": "jane@example"}
337+
338+
The default style is to return minified responses, in line with [Heroku's API design guidelines][heroku-minified-json].
339+
340+
Default: `True`
341+
342+
#### COERCE_DECIMAL_TO_STRING
343+
344+
When returning decimal objects in API representations that do not support a native decimal type, it is normally best to return the value as a string. This avoids the loss of precision that occurs with binary floating point implementations.
345+
346+
When set to `True`, the serializer `DecimalField` class will return strings instead of `Decimal` objects. When set to `False`, serializers will return `Decimal` objects, which the default JSON encoder will return as floats.
347+
348+
Default: `True`
349+
350+
---
351+
312352
## View names and descriptions
313353

314354
**The following settings are used to generate the view names and descriptions, as used in responses to `OPTIONS` requests, and as used in the browsable API.**
@@ -378,4 +418,6 @@ An integer of 0 or more, that may be used to specify the number of application p
378418
Default: `None`
379419

380420
[cite]: http://www.python.org/dev/peps/pep-0020/
421+
[rfc4627]: http://www.ietf.org/rfc/rfc4627.txt
422+
[heroku-minified-json]: https://github.com/interagent/http-api-design#keep-json-minified-in-all-responses
381423
[strftime]: http://docs.python.org/2/library/time.html#time.strftime

docs/api-guide/throttling.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ To create a custom throttle, override `BaseThrottle` and implement `.allow_reque
178178

179179
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`.
180180

181+
If the `.wait()` method is implemented and the request is throttled, then a `Retry-After` header will be included in the response.
182+
181183
## Example
182184

183185
The following is an example of a rate throttle, that will randomly throttle 1 in every 10 requests.

0 commit comments

Comments
 (0)