404
-Page not found -
-Try the homepage, or search the documentation.
-diff --git a/.travis.yml b/.travis.yml index 3eb89dc4f..2134a144f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,10 @@ sudo: false env: - TOX_ENV=py27-flake8 - TOX_ENV=py27-docs + - TOX_ENV=py34-django18 + - TOX_ENV=py33-django18 + - TOX_ENV=py32-django18 + - TOX_ENV=py27-django18 - TOX_ENV=py34-django17 - TOX_ENV=py33-django17 - TOX_ENV=py32-django17 @@ -21,10 +25,18 @@ env: - TOX_ENV=py26-django15 - TOX_ENV=py27-django14 - TOX_ENV=py26-django14 - - TOX_ENV=py34-django18beta - - TOX_ENV=py33-django18beta - - TOX_ENV=py32-django18beta - - TOX_ENV=py27-django18beta + - TOX_ENV=py27-djangomaster + - TOX_ENV=py32-djangomaster + - TOX_ENV=py33-djangomaster + - TOX_ENV=py34-djangomaster + +matrix: + fast_finish: true + allow_failures: + - env: TOX_ENV=py27-djangomaster + - env: TOX_ENV=py32-djangomaster + - env: TOX_ENV=py33-djangomaster + - env: TOX_ENV=py34-djangomaster install: - pip install tox diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000..2b97cc51b --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,24 @@ +# License + +Copyright (c) 2011-2015, Tom Christie +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +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. diff --git a/MANIFEST.in b/MANIFEST.in index d202c86ea..66488aae6 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,5 @@ +include README.md +include LICENSE.md recursive-include rest_framework/static *.js *.css *.png *.eot *.svg *.ttf *.woff recursive-include rest_framework/templates *.html recursive-exclude * __pycache__ diff --git a/README.md b/README.md index 045cdbc46..af8ac58e4 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,9 @@ Full documentation for the project is available at [http://www.django-rest-frame --- -**Note**: We have now released Django REST framework 3.0. For older codebases you may want to refer to the version 2.4.4 [source code](https://github.com/tomchristie/django-rest-framework/tree/version-2.4.x), and [documentation](http://tomchristie.github.io/rest-framework-2-docs/). +**Note**: We have now released Django REST framework 3.1. For older codebases you may want to refer to the version 2.4.4 [source code](https://github.com/tomchristie/django-rest-framework/tree/version-2.4.x), and [documentation](http://tomchristie.github.io/rest-framework-2-docs/). + +For more details see the [3.1 release notes][3.1-announcement] --- @@ -23,7 +25,7 @@ Some reasons you might want to use REST framework: * [Authentication policies][authentication] including optional packages for [OAuth1a][oauth1-section] and [OAuth2][oauth2-section]. * [Serialization][serializers] that supports both [ORM][modelserializer-section] and [non-ORM][serializer-section] data sources. * Customizable all the way down - just use [regular function-based views][functionview-section] if you don't need the [more][generic-views] [powerful][viewsets] [features][routers]. -* [Extensive documentation][index], and [great community support][group]. +* [Extensive documentation][docs], and [great community support][group]. There is a live example API for testing purposes, [available here][sandbox]. @@ -34,7 +36,7 @@ There is a live example API for testing purposes, [available here][sandbox]. # Requirements * Python (2.6.5+, 2.7, 3.2, 3.3, 3.4) -* Django (1.4.11+, 1.5.6+, 1.6.3+, 1.7, 1.8-beta) +* Django (1.4.11+, 1.5.6+, 1.6.3+, 1.7, 1.8) # Installation @@ -154,42 +156,15 @@ If you believe you’ve found something in Django REST framework which has secur Send a description of the issue via email to [rest-framework-security@googlegroups.com][security-mail]. The project maintainers will then work with you to resolve any issues where required, prior to any public disclosure. -# License - -Copyright (c) 2011-2015, Tom Christie -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -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. - [build-status-image]: https://secure.travis-ci.org/tomchristie/django-rest-framework.svg?branch=master [travis]: http://travis-ci.org/tomchristie/django-rest-framework?branch=master -[pypi-version]: https://pypip.in/version/djangorestframework/badge.svg +[pypi-version]: https://img.shields.io/pypi/v/djangorestframework.svg [pypi]: https://pypi.python.org/pypi/djangorestframework [twitter]: https://twitter.com/_tomchristie [group]: https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework -[0.4]: https://github.com/tomchristie/django-rest-framework/tree/0.4.X [sandbox]: http://restframework.herokuapp.com/ -[index]: http://www.django-rest-framework.org/ [oauth1-section]: http://www.django-rest-framework.org/api-guide/authentication/#django-rest-framework-oauth [oauth2-section]: http://www.django-rest-framework.org/api-guide/authentication/#django-oauth-toolkit [serializer-section]: http://www.django-rest-framework.org/api-guide/serializers/#serializers @@ -200,18 +175,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [routers]: http://www.django-rest-framework.org/api-guide/routers/ [serializers]: http://www.django-rest-framework.org/api-guide/serializers/ [authentication]: http://www.django-rest-framework.org/api-guide/authentication/ -[rest-framework-2-announcement]: http://www.django-rest-framework.org/topics/rest-framework-2-announcement/ -[2.1.0-notes]: https://groups.google.com/d/topic/django-rest-framework/Vv2M0CMY9bg/discussion [image]: http://www.django-rest-framework.org/img/quickstart.png -[tox]: http://testrun.org/tox/latest/ - -[tehjones]: https://twitter.com/tehjones/status/294986071979196416 -[wlonk]: https://twitter.com/wlonk/status/261689665952833536 -[laserllama]: https://twitter.com/laserllama/status/328688333750407168 - [docs]: http://www.django-rest-framework.org/ -[urlobject]: https://github.com/zacharyvoase/urlobject -[markdown]: http://pypi.python.org/pypi/Markdown/ -[django-filter]: http://pypi.python.org/pypi/django-filter [security-mail]: mailto:rest-framework-security@googlegroups.com +[3.1-announcement]: http://www.django-rest-framework.org/topics/3.1-announcement/ diff --git a/docs/api-guide/authentication.md b/docs/api-guide/authentication.md old mode 100755 new mode 100644 index fe1be7bf0..2ccf7d721 --- a/docs/api-guide/authentication.md +++ b/docs/api-guide/authentication.md @@ -168,7 +168,6 @@ The `curl` command line tool may be useful for testing token authenticated APIs. If you want every user to have an automatically generated Token, you can simply catch the User's `post_save` signal. from django.conf import settings - from django.contrib.auth import get_user_model from django.db.models.signals import post_save from django.dispatch import receiver from rest_framework.authtoken.models import Token @@ -248,6 +247,10 @@ Unauthenticated responses that are denied permission will result in an `HTTP 403 If you're using an AJAX style API with SessionAuthentication, you'll need to make sure you include a valid CSRF token for any "unsafe" HTTP method calls, such as `PUT`, `PATCH`, `POST` or `DELETE` requests. See the [Django CSRF documentation][csrf-ajax] for more details. +**Warning**: Always use Django's standard login view when creating login pages. This will ensure your login views are properly protected. + +CSRF validation in REST framework works slightly differently to standard Django due to the need to support both session and non-session based authentication to the same views. This means that only authenticated requests require CSRF tokens, and anonymous requests may be sent without CSRF tokens. This behaviour is not suitable for login views, which should always have CSRF validation applied. + # Custom authentication To implement a custom authentication scheme, subclass `BaseAuthentication` and override the `.authenticate(self, request)` method. The method should return a two-tuple of `(user, auth)` if authentication succeeds, or `None` otherwise. diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 0718f58bd..18637f21c 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -1,11 +1,5 @@ source: fields.py ---- - -**Note**: This is the documentation for the **version 3.0** of REST framework. Documentation for [version 2.4](http://tomchristie.github.io/rest-framework-2-docs/) is also available. - ---- - # Serializer fields > Each field in a Form class is responsible not only for validating data, but also for "cleaning" it — normalizing it to a consistent format. @@ -189,6 +183,15 @@ A field that ensures the input is a valid UUID string. The `to_internal_value` m "de305d54-75b4-431b-adb2-eb6b9e546013" +**Signature:** `UUIDField(format='hex_verbose')` + +- `format`: Determines the representation format of the uuid value + - `'hex_verbose'` - The cannoncical hex representation, including hyphens: `"5ce0e9a5-5ffa-654b-cee0-1238041fb31a"` + - `'hex'` - The compact hex representation of the UUID, not including hyphens: `"5ce0e9a55ffa654bcee01238041fb31a"` + - `'int'` - A 128 bit integer representation of the UUID: `"123456789012312313134124512351145145114"` + - `'urn'` - RFC 4122 URN representation of the UUID: `"urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"` + Changing the `format` parameters only affects representation values. All formats are accepted by `to_internal_value` + ## IPAddressField A field that ensures the input is a valid IPv4 or IPv6 string. @@ -319,6 +322,18 @@ Corresponds to `django.db.models.fields.TimeField` Format strings may either be [Python strftime formats][strftime] which explicitly specify the format, or the special string `'iso-8601'`, which indicates that [ISO 8601][iso8601] style times should be used. (eg `'12:34:56.000000'`) +## DurationField + +A Duration representation. +Corresponds to `django.db.models.fields.DurationField` + +The `validated_data` for these fields will contain a `datetime.timedelta` instance. +The representation is a string following this format `'[DD] [HH:[MM:]]ss[.uuuuuu]'`. + +**Note:** This field is only available with Django versions >= 1.8. + +**Signature:** `DurationField()` + --- # Choice selection fields @@ -451,7 +466,7 @@ A field class that does not take a value based on user input, but instead takes For example, to include a field that always provides the current time as part of the serializer validated data, you would use the following: - modified = serializer.HiddenField(default=timezone.now) + modified = serializers.HiddenField(default=timezone.now) The `HiddenField` class is usually only needed if you have some validation that needs to run based on some pre-provided field values, but you do not want to expose all of those fields to the end user. @@ -498,7 +513,7 @@ If you want to create a custom field, you'll need to subclass `Field` and then o The `.to_representation()` method is called to convert the initial datatype into a primitive, serializable datatype. -The `to_internal_value()` method is called to restore a primitive datatype into its internal python representation. This method should raise a `serializer.ValidationError` if the data is invalid. +The `to_internal_value()` method is called to restore a primitive datatype into its internal python representation. This method should raise a `serializers.ValidationError` if the data is invalid. Note that the `WritableField` class that was present in version 2.x no longer exists. You should subclass `Field` and override `to_internal_value()` if the field supports data input. diff --git a/docs/api-guide/filtering.md b/docs/api-guide/filtering.md index b16b6be55..cd0173419 100644 --- a/docs/api-guide/filtering.md +++ b/docs/api-guide/filtering.md @@ -72,7 +72,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 @@ -395,6 +395,10 @@ The following third party packages provide additional filter implementations. The [django-rest-framework-filters package][django-rest-framework-filters] works together with the `DjangoFilterBackend` class, and allows you to easily create filters across relationships, or create multiple filter lookup types for a given field. +## Django REST framework full word search filter + +The [djangorestframework-word-filter][django-rest-framework-word-search-filter] developed as alternative to `filters.SearchFilter` which will search full word in text, or exact match. + [cite]: https://docs.djangoproject.com/en/dev/topics/db/queries/#retrieving-specific-objects-with-filters [django-filter]: https://github.com/alex/django-filter [django-filter-docs]: https://django-filter.readthedocs.org/en/latest/index.html @@ -404,3 +408,4 @@ The [django-rest-framework-filters package][django-rest-framework-filters] works [nullbooleanselect]: https://github.com/django/django/blob/master/django/forms/widgets.py [search-django-admin]: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields [django-rest-framework-filters]: https://github.com/philipn/django-rest-framework-filters +[django-rest-framework-word-search-filter]: https://github.com/trollknurr/django-rest-framework-word-search-filter diff --git a/docs/api-guide/generic-views.md b/docs/api-guide/generic-views.md old mode 100755 new mode 100644 index 61c8e8d88..cb31f5f73 --- a/docs/api-guide/generic-views.md +++ b/docs/api-guide/generic-views.md @@ -1,12 +1,6 @@ source: mixins.py generics.py ---- - -**Note**: This is the documentation for the **version 3.0** of REST framework. Documentation for [version 2.4](http://tomchristie.github.io/rest-framework-2-docs/) is also available. - ---- - # Generic views > Django’s generic views... were developed as a shortcut for common usage patterns... They take certain common idioms and patterns found in view development and abstract them so that you can quickly write common views of data without having to repeat yourself. @@ -57,7 +51,7 @@ For more complex cases you might also want to override various methods on the vi For very simple cases you might want to pass through any class attributes using the `.as_view()` method. For example, your URLconf might include something like the following entry: - url(r'^/users/', ListCreateAPIView.as_view(model=User), name='user-list') + url(r'^/users/', ListCreateAPIView.as_view(queryset=User.objects.all(), serializer_class=UserSerializer), name='user-list') --- @@ -84,10 +78,9 @@ The following attributes control the basic view behavior. The following attributes are used to control pagination when used with list views. -* `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 override 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`. -* `pagination_serializer_class` - The pagination serializer class to use when determining the style of paginated responses. Defaults to the same value as the `DEFAULT_PAGINATION_SERIALIZER_CLASS` setting. -* `page_kwarg` - The name of a URL kwarg or URL query parameter which can be used by the client to control which page is requested. Defaults to `'page'`. +* `pagination_class` - The pagination class that should be used when paginating list results. Defaults to the same value as the `DEFAULT_PAGINATION_CLASS` setting, which is `'rest_framework.pagination.PageNumberPagination'`. + +Note that usage of the `paginate_by`, `paginate_by_param` and `page_kwarg` attributes are now pending deprecation. The `pagination_serializer_class` attribute and `DEFAULT_PAGINATION_SERIALIZER_CLASS` setting have been removed completely. Pagination settings should instead be controlled by overriding a pagination class and setting any configuration attributes there. See the pagination documentation for more details. **Filtering**: @@ -135,14 +128,14 @@ Note that if your API doesn't include any object level permissions, you may opti Returns the classes that should be used to filter the queryset. Defaults to returning the `filter_backends` attribute. -May be overridden to provide more complex behavior with filters, such as using different (or even exlusive) lists of filter_backends depending on different criteria. +May be overridden to provide more complex behavior with filters, such as using different (or even exclusive) lists of filter_backends depending on different criteria. For example: def get_filter_backends(self): - if "geo_route" in self.request.QUERY_PARAMS: + if "geo_route" in self.request.query_params: return (GeoRouteFilter, CategoryFilter) - elif "geo_point" in self.request.QUERY_PARAMS: + elif "geo_point" in self.request.query_params: return (GeoPointFilter, CategoryFilter) return (CategoryFilter,) @@ -200,7 +193,7 @@ You won't typically need to override the following methods, although you might n * `get_serializer_context(self)` - Returns a dictionary containing any extra context that should be supplied to the serializer. Defaults to including `'request'`, `'view'` and `'format'` keys. * `get_serializer(self, instance=None, data=None, files=None, many=False, partial=False, allow_add_remove=False)` - Returns a serializer instance. -* `get_pagination_serializer(self, page)` - Returns a serializer instance to use with paginated data. +* `get_paginated_response(self, data)` - Returns a paginated style `Response` object. * `paginate_queryset(self, queryset)` - Paginate a queryset if required, either returning a page object, or `None` if pagination is not configured for this view. * `filter_queryset(self, queryset)` - Given a queryset, filter it with whichever filter backends are in use, returning a new queryset. diff --git a/docs/api-guide/metadata.md b/docs/api-guide/metadata.md index 247ae988f..017274405 100644 --- a/docs/api-guide/metadata.md +++ b/docs/api-guide/metadata.md @@ -1,11 +1,5 @@ source: metadata.py ---- - -**Note**: This is the documentation for the **version 3.0** of REST framework. Documentation for [version 2.4](http://tomchristie.github.io/rest-framework-2-docs/) is also available. - ---- - # Metadata > [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. @@ -59,7 +53,7 @@ Or you can set the metadata class individually for a view: class APIRoot(APIView): metadata_class = APIRootMetadata - + def get(self, request, format=None): return Response({ ... diff --git a/docs/api-guide/pagination.md b/docs/api-guide/pagination.md index 697ba38d5..687e4dc4b 100644 --- a/docs/api-guide/pagination.md +++ b/docs/api-guide/pagination.md @@ -51,7 +51,8 @@ You can then apply your new style to a view using the `.pagination_class` attrib Or apply the style globally, using the `DEFAULT_PAGINATION_CLASS` settings key. For example: REST_FRAMEWORK = { - 'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination' } + 'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination' + } --- @@ -79,11 +80,11 @@ This pagination style accepts a single number page number in the request query p #### Setup -To enable the `PageNumberPagination` style globally, use the following configuration, modifying the `DEFAULT_PAGE_SIZE` as desired: +To enable the `PageNumberPagination` style globally, use the following configuration, modifying the `PAGE_SIZE` as desired: REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', - 'DEFAULT_PAGE_SIZE': 100 + 'PAGE_SIZE': 100 } On `GenericAPIView` subclasses you may also set the `pagination_class` attribute to select `PageNumberPagination` on a per-view basis. @@ -94,7 +95,7 @@ The `PageNumberPagination` class includes a number of attributes that may be ove To set these attributes you should override the `PageNumberPagination` class, and then enable your custom pagination class as above. -* `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. +* `page_size` - A numeric value indicating the page size. If set, this overrides the `PAGE_SIZE` setting. Defaults to the same value as the `PAGE_SIZE` settings key. * `page_query_param` - A string value indicating the name of the query parameter to use for the pagination control. * `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. * `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. @@ -126,13 +127,13 @@ This pagination style mirrors the syntax used when looking up multiple database #### Setup -To enable the `PageNumberPagination` style globally, use the following configuration: +To enable the `LimitOffsetPagination` style globally, use the following configuration: REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination' } -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. +Optionally, you may also set a `PAGE_SIZE` key. If the `PAGE_SIZE` parameter is also used then the `limit` query parameter will be optional, and may be omitted by the client. On `GenericAPIView` subclasses you may also set the `pagination_class` attribute to select `LimitOffsetPagination` on a per-view basis. @@ -142,7 +143,7 @@ The `LimitOffsetPagination` class includes a number of attributes that may be ov To set these attributes you should override the `LimitOffsetPagination` class, and then enable your custom pagination class as above. -* `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. +* `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 `PAGE_SIZE` settings key. * `limit_query_param` - A string value indicating the name of the "limit" query parameter. Defaults to `'limit'`. * `offset_query_param` - A string value indicating the name of the "offset" query parameter. Defaults to `'offset'`. * `max_limit` - If set this is a numeric value indicating the maximum allowable limit that may be requested by the client. Defaults to `None`. @@ -158,28 +159,33 @@ Cursor based pagination requires that there is a unique, unchanging ordering of 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: -* Provides a consistent pagination view. When used properly `CursorPagination` ensures that the client will never see the same item twice when paging through records. +* Provides a consistent pagination view. When used properly `CursorPagination` ensures that the client will never see the same item twice when paging through records, even when new items are being inserted by other clients during the pagination process. * 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. #### Details and limitations -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. +Proper use of cursor based pagination requires a little attention to detail. You'll need to think about what ordering you want the scheme to be applied against. The default is to order by `"-created"`. This assumes that **there must be a 'created' timestamp field** on the model instances, and will present a "timeline" style paginated view, with the most recently added items first. -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. +You can modify the ordering by overriding the `'ordering'` attribute on the pagination class, or by using the `OrderingFilter` filter class together with `CursorPagination`. When used with `OrderingFilter` you should strongly consider restricting the fields that the user may order by. -**TODO**: Notes on `None`. +Proper usage of cursor pagination should have an ordering field that satisfies the following: -The implementation also supports both forward and reverse pagination, which is often not supported in other implementations. +* Should be an unchanging value, such as a timestamp, slug, or other field that is only set once, on creation. +* Should be unique, or nearly unique. Millisecond precision timestamps are a good example. 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. +* Should be a non-nullable value that can be coerced to a string. +* The field should have a database index. + +Using an ordering field that does not satisfy these constraints will generally still work, but you'll be loosing some of the benefits of cursor pagination. 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. #### Setup -To enable the `CursorPagination` style globally, use the following configuration, modifying the `DEFAULT_PAGE_SIZE` as desired: +To enable the `CursorPagination` style globally, use the following configuration, modifying the `PAGE_SIZE` as desired: REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination', - 'DEFAULT_PAGE_SIZE': 100 + 'PAGE_SIZE': 100 } On `GenericAPIView` subclasses you may also set the `pagination_class` attribute to select `CursorPagination` on a per-view basis. @@ -190,9 +196,9 @@ The `CursorPagination` class includes a number of attributes that may be overrid To set these attributes you should override the `CursorPagination` class, and then enable your custom pagination class as above. -* `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. +* `page_size` = A numeric value indicating the page size. If set, this overrides the `PAGE_SIZE` setting. Defaults to the same value as the `PAGE_SIZE` settings key. * `cursor_query_param` = A string value indicating the name of the "cursor" query parameter. Defaults to `'cursor'`. -* `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`. +* `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 = 'slug'`. Defaults to `-created`. This value may also be overridden by using `OrderingFilter` on the view. * `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"`. --- @@ -208,11 +214,36 @@ Note that the `paginate_queryset` method may set state on the pagination instanc ## Example +Suppose we want to replace the default pagination output style with a modified format that includes the next and previous links under in a nested 'links' key. We could specify a custom pagination class like so: + + class CustomPagination(pagination.PageNumberPagination): + def get_paginated_response(self, data): + return Response({ + 'links': { + 'next': self.get_next_link(), + 'previous': self.get_previous_link() + }, + 'count': self.page.paginator.count, + 'results': data + }) + +We'd then need to setup the custom class in our configuration: + + REST_FRAMEWORK = { + 'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.CustomPagination', + 'PAGE_SIZE': 100 + } + +Note that if you care about how the ordering of keys is displayed in responses in the browsable API you might choose to use an `OrderedDict` when constructing the body of paginated responses, but this is optional. + +## Header based pagination + Let's modify the built-in `PageNumberPagination` style, so that instead of include the pagination links in the body of the response, we'll instead include a `Link` header, in a [similar style to the GitHub API][github-link-pagination]. class LinkHeaderPagination(pagination.PageNumberPagination): def get_paginated_response(self, data): - next_url = self.get_next_link() previous_url = self.get_previous_link() + next_url = self.get_next_link() + previous_url = self.get_previous_link() if next_url is not None and previous_url is not None: link = '<{next_url}; rel="next">, <{previous_url}; rel="prev">' @@ -234,7 +265,7 @@ To have your custom pagination class be used by default, use the `DEFAULT_PAGINA REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.LinkHeaderPagination', - 'DEFAULT_PAGE_SIZE': 10 + 'PAGE_SIZE': 100 } 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: @@ -283,4 +314,4 @@ The [`DRF-extensions` package][drf-extensions] includes a [`PaginateByMaxMixin` [link-header]: ../img/link-header-pagination.png [drf-extensions]: http://chibisov.github.io/drf-extensions/docs/ [paginate-by-max-mixin]: http://chibisov.github.io/drf-extensions/docs/#paginatebymaxmixin -[disqus-cursor-api]: http://cramer.io/2011/03/08/building-cursors-for-the-disqus-api/ \ No newline at end of file +[disqus-cursor-api]: http://cramer.io/2011/03/08/building-cursors-for-the-disqus-api/ diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md index 8731cab08..e86158fef 100644 --- a/docs/api-guide/permissions.md +++ b/docs/api-guide/permissions.md @@ -150,7 +150,7 @@ Similar to `DjangoModelPermissions`, but also allows unauthenticated users to ha This permission class ties into Django's standard [object permissions framework][objectpermissions] that allows per-object permissions on models. In order to use this permission class, you'll also need to add a permission backend that supports object-level permissions, such as [django-guardian][guardian]. -As with `DjangoModelPermissions`, this permission must only be applied to views that have a `.queryset` property. Authorization will only be granted if the user *is authenticated* and has the *relevant per-object permissions* and *relevant model permissions* assigned. +As with `DjangoModelPermissions`, this permission must only be applied to views that have a `.queryset` property or `.get_queryset()` method. Authorization will only be granted if the user *is authenticated* and has the *relevant per-object permissions* and *relevant model permissions* assigned. * `POST` requests require the user to have the `add` permission on the model instance. * `PUT` and `PATCH` requests require the user to have the `change` permission on the model instance. @@ -233,10 +233,6 @@ Also note that the generic views will only check the object-level permissions fo The following third party packages are also available. -## DRF Any Permissions - -The [DRF Any Permissions][drf-any-permissions] packages provides a different permission behavior in contrast to REST framework. Instead of all specified permissions being required, only one of the given permissions has to be true in order to get access to the view. - ## Composed Permissions The [Composed Permissions][composed-permissions] package provides a simple way to define complex and multi-depth (with logic operators) permission objects, using small and reusable components. diff --git a/docs/api-guide/relations.md b/docs/api-guide/relations.md index 50e3b7b59..741943de8 100644 --- a/docs/api-guide/relations.md +++ b/docs/api-guide/relations.md @@ -1,11 +1,5 @@ source: relations.py ---- - -**Note**: This is the documentation for the **version 3.0** of REST framework. Documentation for [version 2.4](http://tomchristie.github.io/rest-framework-2-docs/) is also available. - ---- - # Serializer relations > Bad programmers worry about the code. @@ -52,7 +46,7 @@ In order to explain the various types of relational fields, we'll use a couple o class Meta: unique_together = ('album', 'order') - order_by = 'order' + ordering = ['order'] def __unicode__(self): return '%d: %s' % (self.order, self.title) @@ -279,7 +273,7 @@ If you want to implement a read-write relational field, you must also implement ## Example -For, example, we could define a relational field, to serialize a track to a custom string representation, using its ordering, title, and duration. +For example, we could define a relational field to serialize a track to a custom string representation, using its ordering, title, and duration. import time diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md index 83ded849d..744b4064e 100644 --- a/docs/api-guide/renderers.md +++ b/docs/api-guide/renderers.md @@ -110,7 +110,7 @@ An example of a view that uses `TemplateHTMLRenderer`: class UserDetail(generics.RetrieveAPIView): """ - A view that returns a templated HTML representations of a given user. + A view that returns a templated HTML representation of a given user. """ queryset = User.objects.all() renderer_classes = (TemplateHTMLRenderer,) @@ -135,7 +135,7 @@ See also: `StaticHTMLRenderer` A simple renderer that simply returns pre-rendered HTML. Unlike other renderers, the data passed to the response object should be a string representing the content to be returned. -An example of a view that uses `TemplateHTMLRenderer`: +An example of a view that uses `StaticHTMLRenderer`: @api_view(('GET',)) @renderer_classes((StaticHTMLRenderer,)) @@ -143,7 +143,7 @@ An example of a view that uses `TemplateHTMLRenderer`: data = '
Page not found
+Try the homepage, or search the documentation.
- - - - - - - - -