Skip to content

Commit 8348008

Browse files
committed
Merge pull request #1 from tomchristie/master
Update from tom
2 parents 9141663 + 5aa204e commit 8348008

22 files changed

+351
-69
lines changed

.travis.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ env:
2121
- TOX_ENV=py26-django15
2222
- TOX_ENV=py27-django14
2323
- TOX_ENV=py26-django14
24-
- TOX_ENV=py34-django18alpha
25-
- TOX_ENV=py33-django18alpha
26-
- TOX_ENV=py32-django18alpha
27-
- TOX_ENV=py27-django18alpha
24+
- TOX_ENV=py34-django18beta
25+
- TOX_ENV=py33-django18beta
26+
- TOX_ENV=py32-django18beta
27+
- TOX_ENV=py27-django18beta
2828

2929
install:
3030
- pip install tox

README.md

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

3636
* Python (2.6.5+, 2.7, 3.2, 3.3, 3.4)
37-
* Django (1.4.11+, 1.5.6+, 1.6.3+, 1.7, 1.8-alpha)
37+
* Django (1.4.11+, 1.5.6+, 1.6.3+, 1.7, 1.8-beta)
3838

3939
# Installation
4040

docs/api-guide/authentication.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,10 @@ HTTP Signature (currently a [IETF draft][http-signature-ietf-draft]) provides a
353353

354354
[Djoser][djoser] library provides a set of views to handle basic actions such as registration, login, logout, password reset and account activation. The package works with a custom user model and it uses token based authentication. This is a ready to use REST implementation of Django authentication system.
355355

356+
## django-rest-auth
357+
358+
[Django-rest-auth][django-rest-auth] library provides a set of REST API endpoints for registration, authentication (including social media authentication), password reset, retrieve and update user details, etc. By having these API endpoints, your client apps such as AngularJS, iOS, Android, and others can communicate to your Django backend site independently via REST APIs for user management.
359+
356360
[cite]: http://jacobian.org/writing/rest-worst-practices/
357361
[http401]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2
358362
[http403]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.4
@@ -392,3 +396,4 @@ HTTP Signature (currently a [IETF draft][http-signature-ietf-draft]) provides a
392396
[mohawk]: http://mohawk.readthedocs.org/en/latest/
393397
[mac]: http://tools.ietf.org/html/draft-hammer-oauth-v2-mac-token-05
394398
[djoser]: https://github.com/sunscrapers/djoser
399+
[django-rest-auth]: https://github.com/Tivix/django-rest-auth

docs/api-guide/exceptions.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ Any example validation error might look like this:
4747

4848
You can implement custom exception handling by creating a handler function that converts exceptions raised in your API views into response objects. This allows you to control the style of error responses used by your API.
4949

50-
The function must take a single argument, which is the exception to be handled, and should either return a `Response` object, or return `None` if the exception cannot be handled. If the handler returns `None` then the exception will be re-raised and Django will return a standard HTTP 500 'server error' response.
50+
The function must take a pair of arguments, this first is the exception to be handled, and the second is a dictionary containing any extra context such as the view currently being handled. The exception handler function should either return a `Response` object, or return `None` if the exception cannot be handled. If the handler returns `None` then the exception will be re-raised and Django will return a standard HTTP 500 'server error' response.
5151

5252
For example, you might want to ensure that all error responses include the HTTP status code in the body of the response, like so:
5353

@@ -72,6 +72,8 @@ In order to alter the style of the response, you could write the following custo
7272

7373
return response
7474

75+
The context argument is not used by the default handler, but can be useful if the exception handler needs further information such as the view currently being handled, which can be accessed as `context['view']`.
76+
7577
The exception handler must also be configured in your settings, using the `EXCEPTION_HANDLER` setting key. For example:
7678

7779
REST_FRAMEWORK = {

docs/api-guide/pagination.md

Lines changed: 154 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ You can also set the pagination class on an individual view by using the `pagina
3232
If you want to modify particular aspects of the pagination style, you'll want to override one of the pagination classes, and set the attributes that you want to change.
3333

3434
class LargeResultsSetPagination(PageNumberPagination):
35-
paginate_by = 1000
36-
paginate_by_param = 'page_size'
37-
max_paginate_by = 10000
35+
page_size = 1000
36+
page_size_query_param = 'page_size'
37+
max_page_size = 10000
3838

3939
class StandardResultsSetPagination(PageNumberPagination):
40-
paginate_by = 100
41-
paginate_by_param = 'page_size'
42-
max_paginate_by = 1000
40+
page_size = 100
41+
page_size_query_param = 'page_size'
42+
max_page_size = 1000
4343

4444
You can then apply your new style to a view using the `.pagination_class` attribute:
4545

@@ -59,15 +59,141 @@ Or apply the style globally, using the `DEFAULT_PAGINATION_CLASS` settings key.
5959

6060
## PageNumberPagination
6161

62-
**TODO**
62+
This pagination style accepts a single number page number in the request query parameters.
63+
64+
**Request**:
65+
66+
GET https://api.example.org/accounts/?page=4
67+
68+
**Response**:
69+
70+
HTTP 200 OK
71+
{
72+
"count": 1023
73+
"next": "https://api.example.org/accounts/?page=5",
74+
"previous": "https://api.example.org/accounts/?page=3",
75+
"results": [
76+
77+
]
78+
}
79+
80+
#### Setup
81+
82+
To enable the `PageNumberPagination` style globally, use the following configuration, modifying the `DEFAULT_PAGE_SIZE` as desired:
83+
84+
REST_FRAMEWORK = {
85+
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
86+
'DEFAULT_PAGE_SIZE': 100
87+
}
88+
89+
On `GenericAPIView` subclasses you may also set the `pagination_class` attribute to select `PageNumberPagination` on a per-view basis.
90+
91+
#### Configuration
92+
93+
The `PageNumberPagination` class includes a number of attributes that may be overridden to modify the pagination style.
94+
95+
To set these attributes you should override the `PageNumberPagination` class, and then enable your custom pagination class as above.
96+
97+
* `page_size` - A numeric value indicating the page size. If set, this overrides the `DEFAULT_PAGE_SIZE` setting. Defaults to the same value as the `DEFAULT_PAGE_SIZE` settings key.
98+
* `page_query_param` - A string value indicating the name of the query parameter to use for the pagination control.
99+
* `page_size_query_param` - If set, this is a string value indicating the name of a query parameter that allows the client to set the page size on a per-request basis. Defaults to `None`, indicating that the client may not control the requested page size.
100+
* `max_page_size` - If set, this is a numeric value indicating the maximum allowable requested page size. This attribute is only valid if `page_size_query_param` is also set.
101+
* `last_page_strings` - A list or tuple of string values indicating values that may be used with the `page_query_param` to request the final page in the set. Defaults to `('last',)`
102+
* `template` - The name of a template to use when rendering pagination controls in the browsable API. May be overridden to modify the rendering style, or set to `None` to disable HTML pagination controls completely. Defaults to `"rest_framework/pagination/numbers.html"`.
103+
104+
---
63105

64106
## LimitOffsetPagination
65107

66-
**TODO**
108+
This pagination style mirrors the syntax used when looking up multiple database records. The client includes both a "limit" and an
109+
"offset" query parameter. The limit indicates the maximum number of items to return, and is equivalent to the `page_size` in other styles. The offset indicates the starting position of the query in relation to the complete set of unpaginated items.
110+
111+
**Request**:
112+
113+
GET https://api.example.org/accounts/?limit=100&offset=400
114+
115+
**Response**:
116+
117+
HTTP 200 OK
118+
{
119+
"count": 1023
120+
"next": "https://api.example.org/accounts/?limit=100&offset=500",
121+
"previous": "https://api.example.org/accounts/?limit=100&offset=300",
122+
"results": [
123+
124+
]
125+
}
126+
127+
#### Setup
128+
129+
To enable the `PageNumberPagination` style globally, use the following configuration:
130+
131+
REST_FRAMEWORK = {
132+
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'
133+
}
134+
135+
Optionally, you may also set a `DEFAULT_PAGE_SIZE` key. If the `DEFAULT_PAGE_SIZE` parameter is also used then the `limit` query parameter will be optional, and may be omitted by the client.
136+
137+
On `GenericAPIView` subclasses you may also set the `pagination_class` attribute to select `LimitOffsetPagination` on a per-view basis.
138+
139+
#### Configuration
140+
141+
The `LimitOffsetPagination` class includes a number of attributes that may be overridden to modify the pagination style.
142+
143+
To set these attributes you should override the `LimitOffsetPagination` class, and then enable your custom pagination class as above.
144+
145+
* `default_limit` - A numeric value indicating the limit to use if one is not provided by the client in a query parameter. Defaults to the same value as the `DEFAULT_PAGE_SIZE` settings key.
146+
* `limit_query_param` - A string value indicating the name of the "limit" query parameter. Defaults to `'limit'`.
147+
* `offset_query_param` - A string value indicating the name of the "offset" query parameter. Defaults to `'offset'`.
148+
* `max_limit` - If set this is a numeric value indicating the maximum allowable limit that may be requested by the client. Defaults to `None`.
149+
* `template` - The name of a template to use when rendering pagination controls in the browsable API. May be overridden to modify the rendering style, or set to `None` to disable HTML pagination controls completely. Defaults to `"rest_framework/pagination/numbers.html"`.
150+
151+
---
67152

68153
## CursorPagination
69154

70-
**TODO**
155+
The cursor-based pagination presents an opaque "cursor" indicator that the client may use to page through the result set. This pagination style only presents forward and reverse controls, and does not allow the client to navigate to arbitrary positions.
156+
157+
Cursor based pagination requires that there is a unique, unchanging ordering of items in the result set. This ordering might typically be a creation timestamp on the records, as this presents a consistent ordering to paginate against.
158+
159+
Cursor based pagination is more complex than other schemes. It also requires that the result set presents a fixed ordering, and does not allow the client to arbitrarily index into the result set. However it does provide the following benefits:
160+
161+
* Provides a consistent pagination view. When used properly `CursorPagination` ensures that the client will never see the same item twice when paging through records.
162+
* Supports usage with very large datasets. With extremely large datasets pagination using offset-based pagination styles may become inefficient or unusable. Cursor based pagination schemes instead have fixed-time properties, and do not slow down as the dataset size increases.
163+
164+
#### Details and limitations
165+
166+
This implementation of cursor pagination uses a smart "position plus offset" style that allows it to properly support not-strictly-unique values as the ordering.
167+
168+
It should be noted that using non-unique values the ordering does introduce the possibility of paging artifacts, where pagination consistency is no longer 100% guaranteed.
169+
170+
**TODO**: Notes on `None`.
171+
172+
The implementation also supports both forward and reverse pagination, which is often not supported in other implementations.
173+
174+
For more technical details on the implementation we use for cursor pagination, the ["Building cursors for the Disqus API"][disqus-cursor-api] blog post gives a good overview of the basic approach.
175+
176+
#### Setup
177+
178+
To enable the `CursorPagination` style globally, use the following configuration, modifying the `DEFAULT_PAGE_SIZE` as desired:
179+
180+
REST_FRAMEWORK = {
181+
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination',
182+
'DEFAULT_PAGE_SIZE': 100
183+
}
184+
185+
On `GenericAPIView` subclasses you may also set the `pagination_class` attribute to select `CursorPagination` on a per-view basis.
186+
187+
#### Configuration
188+
189+
The `CursorPagination` class includes a number of attributes that may be overridden to modify the pagination style.
190+
191+
To set these attributes you should override the `CursorPagination` class, and then enable your custom pagination class as above.
192+
193+
* `page_size` = A numeric value indicating the page size. If set, this overrides the `DEFAULT_PAGE_SIZE` setting. Defaults to the same value as the `DEFAULT_PAGE_SIZE` settings key.
194+
* `cursor_query_param` = A string value indicating the name of the "cursor" query parameter. Defaults to `'cursor'`.
195+
* `ordering` = This should be a string, or list of strings, indicating the field against which the cursor based pagination will be applied. For example: `ordering = 'created'`. Any filters on the view which define a `get_ordering` will override this attribute. Defaults to `None`.
196+
* `template` = The name of a template to use when rendering pagination controls in the browsable API. May be overridden to modify the rendering style, or set to `None` to disable HTML pagination controls completely. Defaults to `"rest_framework/pagination/previous_and_next.html"`.
71197

72198
---
73199

@@ -108,7 +234,7 @@ To have your custom pagination class be used by default, use the `DEFAULT_PAGINA
108234

109235
REST_FRAMEWORK = {
110236
'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.LinkHeaderPagination',
111-
'PAGINATE_BY': 10
237+
'DEFAULT_PAGE_SIZE': 10
112238
}
113239

114240
API responses for list endpoints will now include a `Link` header, instead of including the pagination links as part of the body of the response, for example:
@@ -123,8 +249,25 @@ API responses for list endpoints will now include a `Link` header, instead of in
123249

124250
# HTML pagination controls
125251

252+
By default using the pagination classes will cause HTML pagination controls to be displayed in the browsable API. There are two built-in display styles. The `PageNumberPagination` and `LimitOffsetPagination` classes display a list of page numbers with previous and next controls. The `CursorPagination` class displays a simpler style that only displays a previous and next control.
253+
126254
## Customizing the controls
127255

256+
You can override the templates that render the HTML pagination controls. The two built-in styles are:
257+
258+
* `rest_framework/pagination/numbers.html`
259+
* `rest_framework/pagination/previous_and_next.html`
260+
261+
Providing a template with either of these paths in a global template directory will override the default rendering for the relevant pagination classes.
262+
263+
Alternatively you can disable HTML pagination controls completely by subclassing on of the existing classes, setting `template = None` as an attribute on the class. You'll then need to configure your `DEFAULT_PAGINATION_CLASS` settings key to use your custom class as the default pagination style.
264+
265+
#### Low-level API
266+
267+
The low-level API for determining if a pagination class should display the controls or not is exposed as a `display_page_controls` attribute on the pagination instance. Custom pagination classes should be set to `True` in the `paginate_queryset` method if they require the HTML pagination controls to be displayed.
268+
269+
The `.to_html()` and `.get_html_context()` methods may also be overridden in a custom pagination class in order to further customize how the controls are rendered.
270+
128271
---
129272

130273
# Third party packages
@@ -140,3 +283,4 @@ The [`DRF-extensions` package][drf-extensions] includes a [`PaginateByMaxMixin`
140283
[link-header]: ../img/link-header-pagination.png
141284
[drf-extensions]: http://chibisov.github.io/drf-extensions/docs/
142285
[paginate-by-max-mixin]: http://chibisov.github.io/drf-extensions/docs/#paginatebymaxmixin
286+
[disqus-cursor-api]: http://cramer.io/2011/03/08/building-cursors-for-the-disqus-api/

docs/api-guide/testing.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Extends [Django's existing `RequestFactory` class][requestfactory].
1414

1515
## Creating test requests
1616

17-
The `APIRequestFactory` class supports an almost identical API to Django's standard `RequestFactory` class. This means the that standard `.get()`, `.post()`, `.put()`, `.patch()`, `.delete()`, `.head()` and `.options()` methods are all available.
17+
The `APIRequestFactory` class supports an almost identical API to Django's standard `RequestFactory` class. This means that the standard `.get()`, `.post()`, `.put()`, `.patch()`, `.delete()`, `.head()` and `.options()` methods are all available.
1818

1919
from rest_framework.test import APIRequestFactory
2020

@@ -115,7 +115,7 @@ Extends [Django's existing `Client` class][client].
115115

116116
## Making requests
117117

118-
The `APIClient` class supports the same request interface as `APIRequestFactory`. This means the that standard `.get()`, `.post()`, `.put()`, `.patch()`, `.delete()`, `.head()` and `.options()` methods are all available. For example:
118+
The `APIClient` class supports the same request interface as Django's standard `Client` class. This means the that standard `.get()`, `.post()`, `.put()`, `.patch()`, `.delete()`, `.head()` and `.options()` methods are all available. For example:
119119

120120
from rest_framework.test import APIClient
121121

@@ -269,6 +269,6 @@ For example, to add support for using `format='html'` in test requests, you migh
269269
}
270270

271271
[cite]: http://jacobian.org/writing/django-apps-with-buildout/#s-create-a-test-wrapper
272-
[client]: https://docs.djangoproject.com/en/dev/topics/testing/overview/#module-django.test.client
272+
[client]: https://docs.djangoproject.com/en/dev/topics/testing/tools/#the-test-client
273273
[requestfactory]: https://docs.djangoproject.com/en/dev/topics/testing/advanced/#django.test.client.RequestFactory
274274
[configuration]: #configuration

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Some reasons you might want to use REST framework:
5050
REST framework requires the following:
5151

5252
* Python (2.6.5+, 2.7, 3.2, 3.3, 3.4)
53-
* Django (1.4.11+, 1.5.6+, 1.6.3+, 1.7)
53+
* Django (1.4.11+, 1.5.6+, 1.6.3+, 1.7, 1.8-beta)
5454

5555
The following packages are optional:
5656

docs/topics/third-party-resources.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
188188
* [hawkrest][hawkrest] - Provides Hawk HTTP Authorization.
189189
* [djangorestframework-httpsignature][djangorestframework-httpsignature] - Provides an easy to use HTTP Signature Authentication mechanism.
190190
* [djoser][djoser] - Provides a set of views to handle basic actions such as registration, login, logout, password reset and account activation.
191+
* [django-rest-auth][django-rest-auth] - Provides a set of REST API endpoints for registration, authentication (including social media authentication), password reset, retrieve and update user details, etc.
191192

192193
### Permissions
193194

@@ -324,3 +325,4 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
324325
[django-rest-framework-and-angularjs-video]: http://www.youtube.com/watch?v=q8frbgtj020
325326
[web-api-performance-profiling-django-rest-framework]: http://dabapps.com/blog/api-performance-profiling-django-rest-framework/
326327
[api-development-with-django-and-django-rest-framework]: https://bnotions.com/api-development-with-django-and-django-rest-framework/
328+
[django-rest-auth]: https://github.com/Tivix/django-rest-auth/

rest_framework/fields.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,14 @@ def get_attribute(instance, attrs):
7171
except ObjectDoesNotExist:
7272
return None
7373
if is_simple_callable(instance):
74-
instance = instance()
74+
try:
75+
instance = instance()
76+
except (AttributeError, KeyError) as exc:
77+
# If we raised an Attribute or KeyError here it'd get treated
78+
# as an omitted field in `Field.get_attribute()`. Instead we
79+
# raise a ValueError to ensure the exception is not masked.
80+
raise ValueError('Exception raised in callable attribute "{0}"; original exception was: {1}'.format(attr, exc))
81+
7582
return instance
7683

7784

@@ -107,6 +114,8 @@ def __init__(self, default):
107114

108115
def set_context(self, serializer_field):
109116
self.is_update = serializer_field.parent.instance is not None
117+
if callable(self.default) and hasattr(self.default, 'set_context'):
118+
self.default.set_context(serializer_field)
110119

111120
def __call__(self):
112121
if self.is_update:
@@ -1184,7 +1193,7 @@ def to_representation(self, data):
11841193

11851194
class DictField(Field):
11861195
child = _UnvalidatedField()
1187-
initial = []
1196+
initial = {}
11881197
default_error_messages = {
11891198
'not_a_dict': _('Expected a dictionary of items but got type "{input_type}".')
11901199
}

0 commit comments

Comments
 (0)