diff --git a/.gitignore b/.gitignore index 3d5f1043d..e9222c2da 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ MANIFEST !.gitignore !.travis.yml +!.isort.cfg diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 000000000..bd5648e08 --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,6 @@ +[settings] +skip=.tox +atomic=true +multi_line_output=5 +known_third_party=pytest,django +known_first_party=rest_framework diff --git a/.travis.yml b/.travis.yml index 3eb89dc4f..50dc368e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,12 @@ language: python sudo: false env: - - TOX_ENV=py27-flake8 + - TOX_ENV=py27-lint - 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 1117fb8c1..55d73fbcb 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. @@ -26,6 +20,8 @@ Each serializer field class constructor takes at least these arguments. Some Fi ### `read_only` +Read-only fields are included in the API output, but should not be included in the input during create or update operations. Any 'read_only' fields that are incorrectly included in the serializer input will be ignored. + Set this to `True` to ensure that the field is used when serializing a representation, but is not used when creating or updating an instance during deserialization. Defaults to `False` @@ -189,6 +185,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` + ## FilePathField A field whose choices are limited to the filenames in a certain directory on the filesystem @@ -203,6 +208,17 @@ Corresponds to `django.forms.fields.FilePathField`. - `allow_files` - Specifies whether files in the specified location should be included. Default is `True`. Either this or `allow_folders` must be `True`. - `allow_folders` - Specifies whether folders in the specified location should be included. Default is `False`. Either this or `allow_files` must be `True`. +## IPAddressField + +A field that ensures the input is a valid IPv4 or IPv6 string. + +Corresponds to `django.forms.fields.IPAddressField` and `django.forms.fields.GenericIPAddressField`. + +**Signature**: `IPAddressField(protocol='both', unpack_ipv4=False, **options)` + +- `protocol` Limits valid inputs to the specified protocol. Accepted values are 'both' (default), 'IPv4' or 'IPv6'. Matching is case insensitive. +- `unpack_ipv4` Unpacks IPv4 mapped addresses like ::ffff:192.0.2.1. If this option is enabled that address would be unpacked to 192.0.2.1. Default is disabled. Can only be used when protocol is set to 'both'. + --- # Numeric fields @@ -322,6 +338,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 @@ -454,7 +482,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. @@ -501,7 +529,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..c1311c35e 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 @@ -149,6 +149,7 @@ If all you need is simple equality-based filtering, you can set a `filter_fields class ProductList(generics.ListAPIView): queryset = Product.objects.all() serializer_class = ProductSerializer + filter_backends = (filters.DjangoFilterBackend,) filter_fields = ('category', 'in_stock') This will automatically create a `FilterSet` class for the given fields, and will allow you to make requests such as: @@ -174,6 +175,7 @@ For more advanced filtering requirements you can specify a `FilterSet` class tha class ProductList(generics.ListAPIView): queryset = Product.objects.all() serializer_class = ProductSerializer + filter_backends = (filters.DjangoFilterBackend,) filter_class = ProductFilter @@ -395,6 +397,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 +410,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..d219afa11 --- 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**: @@ -131,21 +124,24 @@ For example: Note that if your API doesn't include any object level permissions, you may optionally exclude the `self.check_object_permissions`, and simply return the object from the `get_object_or_404` lookup. -#### `get_filter_backends(self)` - -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. - -For example: - - def get_filter_backends(self): - if "geo_route" in self.request.QUERY_PARAMS: - return (GeoRouteFilter, CategoryFilter) - elif "geo_point" in self.request.QUERY_PARAMS: - return (GeoPointFilter, CategoryFilter) - - return (CategoryFilter,) +#### `filter_queryset(self, queryset)` + +Given a queryset, filter it with whichever filter backends are in use, returning a new queryset. + +For example: + + def filter_queryset(self, queryset): + filter_backends = (CategoryFilter,) + + if 'geo_route' in self.request.query_params: + filter_backends = (GeoRouteFilter, CategoryFilter) + elif 'geo_point' in self.request.query_params: + filter_backends = (GeoPointFilter, CategoryFilter) + + for backend in list(filter_backends): + queryset = backend().filter_queryset(self.request, queryset, view=self) + + return queryset #### `get_serializer_class(self)` @@ -199,8 +195,8 @@ These override points are also particularly useful for adding behavior that occu You won't typically need to override the following methods, although you might need to call into them if you're writing custom views using `GenericAPIView`. * `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_serializer(self, instance=None, data=None, many=False, partial=False)` - Returns a serializer instance. +* `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. @@ -398,6 +394,10 @@ The following third party packages provide additional generic view implementatio The [django-rest-framework-bulk package][django-rest-framework-bulk] implements generic view mixins as well as some common concrete generic views to allow to apply bulk operations via API requests. +## Django Rest Multiple Models + +[Django Rest Multiple Models][django-rest-multiple-models] provides a generic view (and mixin) for sending multiple serialized models and/or querysets via a single API request. + [cite]: https://docs.djangoproject.com/en/dev/ref/class-based-views/#base-vs-generic-views [GenericAPIView]: #genericapiview @@ -407,3 +407,6 @@ The [django-rest-framework-bulk package][django-rest-framework-bulk] implements [UpdateModelMixin]: #updatemodelmixin [DestroyModelMixin]: #destroymodelmixin [django-rest-framework-bulk]: https://github.com/miki725/django-rest-framework-bulk +[django-rest-multiple-models]: https://github.com/Axiologue/DjangoRestMultipleModels + + diff --git a/docs/api-guide/metadata.md b/docs/api-guide/metadata.md index 247ae988f..e12aeb7fd 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({ ... @@ -104,6 +98,12 @@ The following class could be used to limit the information that is returned to ` 'description': view.get_view_description() } +Then configure your settings to use this custom class: + + REST_FRAMEWORK = { + 'DEFAULT_METADATA_CLASS': 'myproject.apps.core.MinimalMetadata' + } + [cite]: http://tools.ietf.org/html/rfc7231#section-4.3.7 [no-options]: https://www.mnot.net/blog/2012/10/29/NO_OPTIONS [json-schema]: http://json-schema.org/ diff --git a/docs/api-guide/pagination.md b/docs/api-guide/pagination.md index 697ba38d5..15ebc6229 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,18 +214,43 @@ 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">' + link = '<{next_url}>; rel="next", <{previous_url}>; rel="prev"' elif next_url is not None: - link = '<{next_url}; rel="next">' + link = '<{next_url}>; rel="next"' elif previous_url is not None: - link = '<{previous_url}; rel="prev">' + link = '<{previous_url}>; rel="prev"' else: link = '' @@ -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/parsers.md b/docs/api-guide/parsers.md index c242f878b..d5975abd2 100644 --- a/docs/api-guide/parsers.md +++ b/docs/api-guide/parsers.md @@ -144,17 +144,16 @@ By default this will include the following keys: `view`, `request`, `args`, `kwa The following is an example plaintext parser that will populate the `request.data` property with a string representing the body of the request. class PlainTextParser(BaseParser): - """ - Plain text parser. - """ - - media_type = 'text/plain' - - def parse(self, stream, media_type=None, parser_context=None): """ - Simply return a string representing the body of the request. + Plain text parser. """ - return stream.read() + media_type = 'text/plain' + + def parse(self, stream, media_type=None, parser_context=None): + """ + Simply return a string representing the body of the request. + """ + return stream.read() --- diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md index 8731cab08..31fe4c309 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. @@ -190,6 +190,16 @@ If you need to test if a request is a read operation or a write operation, you s --- +Custom permissions will raise a `PermissionDenied` exception if the test fails. To change the error message associated with the exception, implement a `message` attribute directly on your custom permission. Otherwise the `default_detail` attribute from `PermissionDenied` will be used. + + from rest_framework import permissions + + class CustomerAccessPermission(permissions.BasePermission): + message = 'Adding customers not allowed.' + + def has_permission(self, request, view): + ... + ## Examples The following is an example of a permission class that checks the incoming request's IP address against a blacklist, and denies the request if the IP has been blacklisted. @@ -233,10 +243,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..a673c2fcc 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) @@ -122,6 +116,8 @@ By default this field is read-write, although you can change this behavior using * `queryset` - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set `read_only=True`. * `many` - If applied to a to-many relationship, you should set this argument to `True`. * `allow_null` - If set to `True`, the field will accept values of `None` or the empty string for nullable relationships. Defaults to `False`. +* `pk_field` - Set to a field to control serialization/deserialization of the primary key's value. For example, `pk_field=UUIDField(format='hex')` would serialize a UUID primary key into its compact hex representation. + ## HyperlinkedRelatedField @@ -260,17 +256,64 @@ For example, the following serializer: Would serialize to a nested representation like this: + >>> album = Album.objects.create(album_name="The Grey Album", artist='Danger Mouse') + >>> Track.objects.create(album=album, order=1, title='Public Service Announcement', duration=245) + + >>> Track.objects.create(album=album, order=2, title='What More Can I Say', duration=264) + + >>> Track.objects.create(album=album, order=3, title='Encore', duration=159) + + >>> serializer = AlbumSerializer(instance=album) + >>> serializer.data { 'album_name': 'The Grey Album', 'artist': 'Danger Mouse', 'tracks': [ - {'order': 1, 'title': 'Public Service Announcement'}, - {'order': 2, 'title': 'What More Can I Say'}, - {'order': 3, 'title': 'Encore'}, + {'order': 1, 'title': 'Public Service Announcement', 'duration': 245}, + {'order': 2, 'title': 'What More Can I Say', 'duration': 264}, + {'order': 3, 'title': 'Encore', 'duration': 159}, ... ], } +# Writable nested serializers + +Be default nested serializers are read-only. If you want to to support write-operations to a nested serializer field you'll need to create either or both of the `create()` and/or `update()` methods, in order to explicitly specify how the child relationships should be saved. + + class TrackSerializer(serializers.ModelSerializer): + class Meta: + model = Track + fields = ('order', 'title') + + class AlbumSerializer(serializers.ModelSerializer): + tracks = TrackSerializer(many=True) + + class Meta: + model = Album + fields = ('album_name', 'artist', 'tracks') + + def create(self, validated_data): + tracks_data = validated_data.pop('tracks') + album = Album.objects.create(**validated_data) + for track_data in tracks_data: + Track.objects.create(album=album, **track_data) + return album + + >>> data = { + 'album_name': 'The Grey Album', + 'artist': 'Danger Mouse', + 'tracks': [ + {'order': 1, 'title': 'Public Service Announcement', 'duration': 245}, + {'order': 2, 'title': 'What More Can I Say', 'duration': 264}, + {'order': 3, 'title': 'Encore', 'duration': 159}, + ], + } + >>> serializer = AlbumSerializer(data=data) + >>> serializer.is_valid() + True + >>> serializer.save() + + # Custom relational fields To implement a custom relational field, you should override `RelatedField`, and implement the `.to_representation(self, value)` method. This method takes the target of the field as the `value` argument, and should return the representation that should be used to serialize the target. The `value` argument will typically be a model instance. @@ -279,7 +322,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..1d1b4691e 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 = '

Hello, world

' return Response(data) -You can use `TemplateHTMLRenderer` either to return regular HTML pages using REST framework, or to return both HTML and API responses from a single endpoint. +You can use `StaticHTMLRenderer` either to return regular HTML pages using REST framework, or to return both HTML and API responses from a single endpoint. **.media_type**: `text/html` @@ -157,7 +157,7 @@ See also: `TemplateHTMLRenderer` Renders data returned by a serializer into an HTML form. The output of this renderer does not include the enclosing `
` tags or an submit actions, as you'll probably need those to include the desired method and URL. Also note that the `HTMLFormRenderer` does not yet support including field error messages. -Note that the template used by the `HTMLFormRenderer` class, and the context submitted to it **may be subject to change**. If you need to use this renderer class it is advised that you either make a local copy of the class and templates, or follow the release note on REST framework upgrades closely. +**Note**: The `HTMLFormRenderer` class is intended for internal use with the browsable API. It should not be considered a fully documented or stable API. The template used by the `HTMLFormRenderer` class, and the context submitted to it **may be subject to change**. If you need to use this renderer class it is advised that you either make a local copy of the class and templates, or follow the release note on REST framework upgrades closely. **.media_type**: `text/html` @@ -181,7 +181,7 @@ Renders data into HTML for the Browsable API. This renderer will determine whic #### Customizing BrowsableAPIRenderer -By default the response content will be rendered with the highest priority renderer apart from `BrowseableAPIRenderer`. If you need to customize this behavior, for example to use HTML as the default return format, but use JSON in the browsable API, you can do so by overriding the `get_default_renderer()` method. For example: +By default the response content will be rendered with the highest priority renderer apart from `BrowsableAPIRenderer`. If you need to customize this behavior, for example to use HTML as the default return format, but use JSON in the browsable API, you can do so by overriding the `get_default_renderer()` method. For example: class CustomBrowsableAPIRenderer(BrowsableAPIRenderer): def get_default_renderer(self, view): @@ -406,7 +406,7 @@ Modify your REST framework settings. REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': ( - 'rest_framework_yaml.renderers.JSONPRenderer', + 'rest_framework_jsonp.renderers.JSONPRenderer', ), } diff --git a/docs/api-guide/requests.md b/docs/api-guide/requests.md index c993dfae5..658a5ffd6 100644 --- a/docs/api-guide/requests.md +++ b/docs/api-guide/requests.md @@ -1,11 +1,5 @@ source: request.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. - ---- - # Requests > If you're doing REST-based web service stuff ... you should ignore request.POST. diff --git a/docs/api-guide/routers.md b/docs/api-guide/routers.md index 222b6cd25..d73606da2 100644 --- a/docs/api-guide/routers.md +++ b/docs/api-guide/routers.md @@ -290,14 +290,14 @@ The following third party packages are also available. The [drf-nested-routers package][drf-nested-routers] provides routers and relationship fields for working with nested resources. -## wq.db +## ModelRouter (wq.db.rest) -The [wq.db package][wq.db] provides an advanced [Router][wq.db-router] class (and singleton instance) that extends `DefaultRouter` with a `register_model()` API. Much like Django's `admin.site.register`, the only required argument to `app.router.register_model` is a model class. Reasonable defaults for a url prefix and viewset will be inferred from the model and global configuration. +The [wq.db package][wq.db] provides an advanced [ModelRouter][wq.db-router] class (and singleton instance) that extends `DefaultRouter` with a `register_model()` API. Much like Django's `admin.site.register`, the only required argument to `rest.router.register_model` is a model class. Reasonable defaults for a url prefix, serializer, and viewset will be inferred from the model and global configuration. - from wq.db.rest import app + from wq.db import rest from myapp.models import MyModel - app.router.register_model(MyModel) + rest.router.register_model(MyModel) ## DRF-extensions @@ -307,7 +307,7 @@ The [`DRF-extensions` package][drf-extensions] provides [routers][drf-extensions [route-decorators]: viewsets.md#marking-extra-actions-for-routing [drf-nested-routers]: https://github.com/alanjds/drf-nested-routers [wq.db]: http://wq.io/wq.db -[wq.db-router]: http://wq.io/docs/app.py +[wq.db-router]: http://wq.io/docs/router [drf-extensions]: http://chibisov.github.io/drf-extensions/docs/ [drf-extensions-routers]: http://chibisov.github.io/drf-extensions/docs/#routers [drf-extensions-nested-viewsets]: http://chibisov.github.io/drf-extensions/docs/#nested-routes diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index 940eb4249..2f13bd2a4 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -1,11 +1,5 @@ source: serializers.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. - ---- - # Serializers > Expanding the usefulness of the serializers is something that we would @@ -23,7 +17,7 @@ The serializers in REST framework work very similarly to Django's `Form` and `Mo Let's start by creating a simple object we can use for example purposes: from datetime import datetime - + class Comment(object): def __init__(self, email, content, created=None): self.email = email @@ -350,7 +344,7 @@ Here's an example for an `update()` method on our previous `UserSerializer` clas return instance -Because the behavior of nested creates and updates can be ambiguous, and may require complex dependancies between related models, REST framework 3 requires you to always write these methods explicitly. The default `ModelSerializer` `.create()` and `.update()` methods do not include support for writable nested representations. +Because the behavior of nested creates and updates can be ambiguous, and may require complex dependencies between related models, REST framework 3 requires you to always write these methods explicitly. The default `ModelSerializer` `.create()` and `.update()` methods do not include support for writable nested representations. It is possible that a third party package, providing automatic support some kinds of automatic writable nested representations may be released alongside the 3.1 release. @@ -484,7 +478,7 @@ The default `ModelSerializer` uses primary keys for relationships, but you can a The `depth` option should be set to an integer value that indicates the depth of relationships that should be traversed before reverting to a flat representation. -If you want to customize the way the serialization is done (e.g. using `allow_add_remove`) you'll need to define the field yourself. +If you want to customize the way the serialization is done you'll need to define the field yourself. ## Specifying fields explicitly @@ -818,7 +812,7 @@ There are four methods that can be overridden, depending on what functionality y * `.to_representation()` - Override this to support serialization, for read operations. * `.to_internal_value()` - Override this to support deserialization, for write operations. -* `.create()` and `.update()` - Overide either or both of these to support saving instances. +* `.create()` and `.update()` - Override either or both of these to support saving instances. Because this class provides the same interface as the `Serializer` class, you can use it with the existing generic class based views exactly as you would for a regular `Serializer` or `ModelSerializer`. diff --git a/docs/api-guide/settings.md b/docs/api-guide/settings.md index 5af429d16..6fdb77c86 100644 --- a/docs/api-guide/settings.md +++ b/docs/api-guide/settings.md @@ -273,6 +273,8 @@ Default: `'accept'` The name of a URL parameter that may be used to override the default `Accept` header based content negotiation. +If the value of this setting is `None` then URL format overloading will be disabled. + Default: `'format'` --- diff --git a/docs/api-guide/testing.md b/docs/api-guide/testing.md index 8a848c20c..dd3295c4f 100644 --- a/docs/api-guide/testing.md +++ b/docs/api-guide/testing.md @@ -65,7 +65,7 @@ When testing views directly using a request factory, it's often convenient to be To forcibly authenticate a request, use the `force_authenticate()` method. - from rest_framework.tests import force_authenticate + from rest_framework.test import force_authenticate factory = APIRequestFactory() user = User.objects.get(username='olivia') diff --git a/docs/api-guide/validators.md b/docs/api-guide/validators.md index 8f5a89298..e54ebfc38 100644 --- a/docs/api-guide/validators.md +++ b/docs/api-guide/validators.md @@ -1,11 +1,5 @@ source: validators.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. - ---- - # Validators > Validators can be useful for re-using validation logic between different types of fields. @@ -33,7 +27,7 @@ When you're using `ModelSerializer` all of this is handled automatically for you As an example of how REST framework uses explicit validation, we'll take a simple model class that has a field with a uniqueness constraint. class CustomerReportRecord(models.Model): - time_raised = models.DateTimeField(default=timezone.now, editable=False) + time_raised = models.DateTimeField(default=timezone.now, editable=False) reference = models.CharField(unique=True, max_length=20) description = models.TextField() @@ -43,7 +37,7 @@ Here's a basic `ModelSerializer` that we can use for creating or updating instan class Meta: model = CustomerReportRecord -If we open up the Django shell using `manage.py shell` we can now +If we open up the Django shell using `manage.py shell` we can now >>> from project.example.serializers import CustomerReportSerializer >>> serializer = CustomerReportSerializer() @@ -178,7 +172,7 @@ REST framework includes a couple of defaults that may be useful in this context. A default class that can be used to represent the current user. In order to use this, the 'request' must have been provided as part of the context dictionary when instantiating the serializer. owner = serializers.HiddenField( - default=CurrentUserDefault() + default=serializers.CurrentUserDefault() ) #### CreateOnlyDefault @@ -204,18 +198,18 @@ A validator may be any callable that raises a `serializers.ValidationError` on f def even_number(value): if value % 2 != 0: - raise serializers.ValidationError('This field must be an even number.') + raise serializers.ValidationError('This field must be an even number.') ## Class based To write a class based validator, use the `__call__` method. Class based validators are useful as they allow you to parameterize and reuse behavior. - class MultipleOf: + class MultipleOf(object): def __init__(self, base): self.base = base - + def __call__(self, value): - if value % self.base != 0 + if value % self.base != 0: message = 'This field must be a multiple of %d.' % self.base raise serializers.ValidationError(message) diff --git a/docs/api-guide/versioning.md b/docs/api-guide/versioning.md index 30dfeb2c0..482943b86 100644 --- a/docs/api-guide/versioning.md +++ b/docs/api-guide/versioning.md @@ -3,7 +3,7 @@ source: versioning.py # Versioning > Versioning an interface is just a "polite" way to kill deployed clients. -> +> > — [Roy Fielding][cite]. API versioning allows you to alter behavior between different clients. REST framework provides for a number of different versioning schemes. @@ -31,6 +31,8 @@ How you vary the API behavior is up to you, but one example you might typically The `reverse` function included by REST framework ties in with the versioning scheme. You need to make sure to include the current `request` as a keyword argument, like so. + from rest_framework.reverse import reverse + reverse('bookings-list', request=request) The above function will apply any URL transformations appropriate to the request version. For example: @@ -69,9 +71,22 @@ You can also set the versioning scheme on an individual view. Typically you won' The following settings keys are also used to control versioning: * `DEFAULT_VERSION`. The value that should be used for `request.version` when no versioning information is present. Defaults to `None`. -* `ALLOWED_VERSIONS`. If set, this value will restrict the set of versions that may be returned by the versioning scheme, and will raise an error if the provided version if not in this set. Defaults to `None`. +* `ALLOWED_VERSIONS`. If set, this value will restrict the set of versions that may be returned by the versioning scheme, and will raise an error if the provided version if not in this set. Note that the value used for the `DEFAULT_VERSION` setting is always considered to be part of the `ALLOWED_VERSIONS` set. Defaults to `None`. * `VERSION_PARAMETER`. The string that should used for any versioning parameters, such as in the media type or URL query parameters. Defaults to `'version'`. +You can also set your versioning class plus those three values on a per-view or a per-viewset basis by defining your own versioning scheme and using the `default_version`, `allowed_versions` and `version_param` class variables. For example, if you want to use `URLPathVersioning`: + + from rest_framework.versioning import URLPathVersioning + from rest_framework.views import APIView + + class ExampleVersioning(URLPathVersioning): + default_version = ... + allowed_versions = ... + version_param = ... + + class ExampleView(APIVIew): + versioning_class = ExampleVersioning + --- # API Reference @@ -103,7 +118,7 @@ Your client requests would now look like this: Host: example.com Accept: application/vnd.megacorp.bookings+json; version=1.0 -## URLParameterVersioning +## URLPathVersioning This scheme requires the client to specify the version as part of the URL path. @@ -115,12 +130,12 @@ Your URL conf must include a pattern that matches the version with a `'version'` urlpatterns = [ url( - r'^(?P{v1,v2})/bookings/$', + r'^(?P[v1|v2]+)/bookings/$', bookings_list, name='bookings-list' ), url( - r'^(?P{v1,v2})/bookings/(?P[0-9]+)/$', + r'^(?P[v1|v2]+)/bookings/(?P[0-9]+)/$', bookings_detail, name='bookings-detail' ) diff --git a/docs/api-guide/viewsets.md b/docs/api-guide/viewsets.md index 4fd7aa84c..0452a0f7b 100644 --- a/docs/api-guide/viewsets.md +++ b/docs/api-guide/viewsets.md @@ -27,7 +27,7 @@ Let's define a simple viewset that can be used to list or retrieve all the users class UserViewSet(viewsets.ViewSet): """ - A simple ViewSet that for listing or retrieving users. + A simple ViewSet for listing or retrieving users. """ def list(self, request): queryset = User.objects.all() @@ -136,8 +136,13 @@ For example: @list_route() def recent_users(self, request): recent_users = User.objects.all().order('-last_login') + page = self.paginate_queryset(recent_users) - serializer = self.get_pagination_serializer(page) + if page is not None: + serializer = self.get_serializer(page, many=True) + return self.get_paginated_response(serializer.data) + + serializer = self.get_serializer(recent_users, many=True) return Response(serializer.data) The decorators can additionally take extra arguments that will be set for the routed view only. For example... diff --git a/docs/index.md b/docs/index.md index 91766a0b8..27c50fee8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,17 +1,20 @@

- + - - + + + - + + +

--- -**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. +**Note**: This is the documentation for the **version 3.1** of REST framework. Documentation for [version 2.4](http://tomchristie.github.io/rest-framework-2-docs/) is also available. -For more details see the [3.0 release notes][3.0-announcement]. +For more details see the [3.1 release notes][3.1-announcement]. --- @@ -50,7 +53,7 @@ Some reasons you might want to use REST framework: REST framework requires the following: * 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) The following packages are optional: @@ -248,8 +251,6 @@ 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. -[travis]: http://travis-ci.org/tomchristie/django-rest-framework?branch=master -[travis-build-image]: https://secure.travis-ci.org/tomchristie/django-rest-framework.png?branch=master [mozilla]: http://www.mozilla.org/en-US/about/ [eventbrite]: https://www.eventbrite.co.uk/about/ [markdown]: http://pypi.python.org/pypi/Markdown/ diff --git a/docs/topics/3.0-announcement.md b/docs/topics/3.0-announcement.md index 59fe779ca..89f9e8001 100644 --- a/docs/topics/3.0-announcement.md +++ b/docs/topics/3.0-announcement.md @@ -940,7 +940,7 @@ The default JSON renderer will return float objects for un-coerced `Decimal` ins * The serializer `ChoiceField` does not currently display nested choices, as was the case in 2.4. This will be address as part of 3.1. * Due to the new templated form rendering, the 'widget' option is no longer valid. This means there's no easy way of using third party "autocomplete" widgets for rendering select inputs that contain a large number of choices. You'll either need to use a regular select or a plain text input. We may consider addressing this in 3.1 or 3.2 if there's sufficient demand. * Some of the default validation error messages were rewritten and might no longer be pre-translated. You can still [create language files with Django][django-localization] if you wish to localize them. -* `APIException` subclasses could previously take could previously take any arbitrary type in the `detail` argument. These exceptions now use translatable text strings, and as a result call `force_text` on the `detail` argument, which *must be a string*. If you need complex arguments to an `APIException` class, you should subclass it and override the `__init__()` method. Typically you'll instead want to use a custom exception handler to provide for non-standard error responses. +* `APIException` subclasses could previously take any arbitrary type in the `detail` argument. These exceptions now use translatable text strings, and as a result call `force_text` on the `detail` argument, which *must be a string*. If you need complex arguments to an `APIException` class, you should subclass it and override the `__init__()` method. Typically you'll instead want to use a custom exception handler to provide for non-standard error responses. --- diff --git a/docs/topics/3.1-announcement.md b/docs/topics/3.1-announcement.md index f500101c5..80d4007eb 100644 --- a/docs/topics/3.1-announcement.md +++ b/docs/topics/3.1-announcement.md @@ -17,6 +17,15 @@ Some highlights include: The pagination API has been improved, making it both easier to use, and more powerful. +A guide to the headline features follows. For full details, see [the pagination documentation][pagination]. + +Note that as a result of this work a number of settings keys and generic view attributes are now moved to pending deprecation. Controlling pagination styles is now largely handled by overriding a pagination class and modifying its configuration attributes. + +* The `PAGINATE_BY` settings key will continue to work but is now pending deprecation. The more obviously named `PAGE_SIZE` settings key should now be used instead. +* The `PAGINATE_BY_PARAM`, `MAX_PAGINATE_BY` settings keys will continue to work but are now pending deprecation, in favor of setting configuration attributes on the configured pagination class. +* The `paginate_by`, `page_query_param`, `paginate_by_param` and `max_paginate_by` generic view attributes will continue to work but are now pending deprecation, in favor of setting configuration attributes on the configured pagination class. +* The `pagination_serializer_class` view attribute and `DEFAULT_PAGINATION_SERIALIZER_CLASS` settings key **are no longer valid**. The pagination API does not use serializers to determine the output format, and you'll need to instead override the `get_paginated_response` method on a pagination class in order to specify how the output format is controlled. + #### New pagination schemes. Until now, there has only been a single built-in pagination style in REST framework. We now have page, limit/offset and cursor based schemes included by default. @@ -43,7 +52,7 @@ For more information, see the [custom pagination styles](../api-guide/pagination ## Versioning -We've made it easier to build versioned APIs. Built-in schemes for versioning include both URL based and Accept header based variations. +We've made it [easier to build versioned APIs][versioning]. Built-in schemes for versioning include both URL based and Accept header based variations. When using a URL based scheme, hyperlinked serializers will resolve relationships to the same API version as used on the incoming request. @@ -71,7 +80,7 @@ The output representation would match the version used on the incoming request. ## Internationalization -REST framework now includes a built-in set of translations, and supports internationalized error responses. This allows you to either change the default language, or to allow clients to specify the language via the `Accept-Language` header. +REST framework now includes a built-in set of translations, and [supports internationalized error responses][internationalization]. This allows you to either change the default language, or to allow clients to specify the language via the `Accept-Language` header. You can change the default language by using the standard Django `LANGUAGE_CODE` setting: @@ -136,7 +145,7 @@ If you're building a new 1.8 project, then you should probably consider using `U The serializer redesign in 3.0 did not include any public API for modifying how ModelSerializer classes automatically generate a set of fields from a given mode class. We've now re-introduced an API for this, allowing you to create new ModelSerializer base classes that behave differently, such as using a different default style for relationships. -For more information, see the documentation on [customizing field mappings](../api-guide/serializers/#customizing-field-mappings) for ModelSerializer classes. +For more information, see the documentation on [customizing field mappings][customizing-field-mappings] for ModelSerializer classes. --- @@ -194,3 +203,7 @@ The next focus will be on HTML renderings of API output and will include: This will either be made as a single 3.2 release, or split across two separate releases, with the HTML forms and filter controls coming in 3.2, and the admin-style interface coming in a 3.3 release. [custom-exception-handler]: ../api-guide/exceptions.md#custom-exception-handling +[pagination]: ../api-guide/pagination.md +[versioning]: ../api-guide/versioning.md +[internationalization]: internationalization.md +[customizing-field-mappings]: ../api-guide/serializers.md#customizing-field-mappings diff --git a/docs/topics/browsable-api.md b/docs/topics/browsable-api.md index 2879db74b..bdc5b19c6 100644 --- a/docs/topics/browsable-api.md +++ b/docs/topics/browsable-api.md @@ -35,7 +35,7 @@ To replace the default theme, add a `bootstrap_theme` block to your `api.html` a {% endblock %} -A suitable replacement theme can be generated using Bootstrap's [Customize Tool][bcustomize]. There are also pre-made themes available at [Bootswatch][bswatch]. To use any of the Bootswatch themes, simply download the theme's `bootstrap.min.css` file, add it to your project, and replace the default one as described above. +Suitable pre-made replacement themes are available at [Bootswatch][bswatch]. To use any of the Bootswatch themes, simply download the theme's `bootstrap.min.css` file, add it to your project, and replace the default one as described above. You can also change the navbar variant, which by default is `navbar-inverse`, using the `bootstrap_navbar_variant` block. The empty `{% block bootstrap_navbar_variant %}{% endblock %}` will use the original Bootstrap navbar style. diff --git a/docs/topics/project-management.md b/docs/topics/project-management.md index 4926f3554..8c1fdfd99 100644 --- a/docs/topics/project-management.md +++ b/docs/topics/project-management.md @@ -97,9 +97,15 @@ The following template should be used for the description of the issue, and serv Release manager is @***. Pull request is #***. + During development cycle: + + - [ ] Upload the new content to be translated to [transifex](http://www.django-rest-framework.org/topics/project-management/#translations). + + Checklist: - [ ] Create pull request for [release notes](https://github.com/tomchristie/django-rest-framework/blob/master/docs/topics/release-notes.md) based on the [*.*.* milestone](https://github.com/tomchristie/django-rest-framework/milestones/***). + - [ ] Update the translations from [transifex](http://www.django-rest-framework.org/topics/project-management/#translations). - [ ] Ensure the pull request increments the version to `*.*.*` in [`restframework/__init__.py`](https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/__init__.py). - [ ] Confirm with @tomchristie that release is finalized and ready to go. - [ ] Ensure that release date is included in pull request. diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md index 51eb45c37..4bfcb0033 100644 --- a/docs/topics/release-notes.md +++ b/docs/topics/release-notes.md @@ -38,8 +38,73 @@ You can determine your currently installed version using `pip freeze`: --- -## 3.0.x series +## 3.1.x series +### 3.1.3 + +**Date**: [4th June 2015][3.1.3-milestone]. + +* Add `DurationField`. ([#2481][gh2481], [#2989][gh2989]) +* Add `format` argument to `UUIDField`. ([#2788][gh2788], [#3000][gh3000]) +* `MultipleChoiceField` empties incorrectly on a partial update using multipart/form-data ([#2993][gh2993], [#2894][gh2894]) +* Fix a bug in options related to read-only `RelatedField`. ([#2981][gh2981], [#2811][gh2811]) +* Fix nested serializers with `unique_together` relations. ([#2975][gh2975]) +* Allow unexpected values for `ChoiceField`/`MultipleChoiceField` representations. ([#2839][gh2839], [#2940][gh2940]) +* Rollback the transaction on error if `ATOMIC_REQUESTS` is set. ([#2887][gh2887], [#2034][gh2034]) +* Set the action on a view when override_method regardless of its None-ness. ([#2933][gh2933]) +* `DecimalField` accepts `2E+2` as 200 and validates decimal place correctly. ([#2948][gh2948], [#2947][gh2947]) +* Support basic authentication with custom `UserModel` that change `username`. ([#2952][gh2952]) +* `IPAddressField` improvements. ([#2747][gh2747], [#2618][gh2618], [#3008][gh3008]) +* Improve `DecimalField` for easier subclassing. ([#2695][gh2695]) + + +### 3.1.2 + +**Date**: [13rd May 2015][3.1.2-milestone]. + +* `DateField.to_representation` can handle str and empty values. ([#2656][gh2656], [#2687][gh2687], [#2869][gh2869]) +* Use default reason phrases from HTTP standard. ([#2764][gh2764], [#2763][gh2763]) +* Raise error when `ModelSerializer` used with abstract model. ([#2757][gh2757], [#2630][gh2630]) +* Handle reversal of non-API view_name in `HyperLinkedRelatedField` ([#2724][gh2724], [#2711][gh2711]) +* Dont require pk strictly for related fields. ([#2745][gh2745], [#2754][gh2754]) +* Metadata detects null boolean field type. ([#2762][gh2762]) +* Proper handling of depth in nested serializers. ([#2798][gh2798]) +* Display viewset without paginator. ([#2807][gh2807]) +* Don't check for deprecated `.model` attribute in permissions ([#2818][gh2818]) +* Restrict integer field to integers and strings. ([#2835][gh2835], [#2836][gh2836]) +* Improve `IntegerField` to use compiled decimal regex. ([#2853][gh2853]) +* Prevent empty `queryset` to raise AssertionError. ([#2862][gh2862]) +* `DjangoModelPermissions` rely on `get_queryset`. ([#2863][gh2863]) +* Check `AcceptHeaderVersioning` with content negotiation in place. ([#2868][gh2868]) +* Allow `DjangoObjectPermissions` to use views that define `get_queryset`. ([#2905][gh2905]) + + +### 3.1.1 + +**Date**: [23rd March 2015][3.1.1-milestone]. + +* **Security fix**: Escape tab switching cookie name in browsable API. +* Display input forms in browsable API if `serializer_class` is used, even when `get_serializer` method does not exist on the view. ([#2743][gh2743]) +* Use a password input for the AuthTokenSerializer. ([#2741][gh2741]) +* Fix missing anchor closing tag after next button. ([#2691][gh2691]) +* Fix `lookup_url_kwarg` handling in viewsets. ([#2685][gh2685], [#2591][gh2591]) +* Fix problem with importing `rest_framework.views` in `apps.py` ([#2678][gh2678]) +* LimitOffsetPagination raises `TypeError` if PAGE_SIZE not set ([#2667][gh2667], [#2700][gh2700]) +* German translation for `min_value` field error message references `max_value`. ([#2645][gh2645]) +* Remove `MergeDict`. ([#2640][gh2640]) +* Support serializing unsaved models with related fields. ([#2637][gh2637], [#2641][gh2641]) +* Allow blank/null on radio.html choices. ([#2631][gh2631]) + + +### 3.1.0 + +**Date**: [5th March 2015][3.1.0-milestone]. + +For full details see the [3.1 release announcement](3.1-announcement.md). + +--- + +## 3.0.x series ### 3.0.5 @@ -137,7 +202,7 @@ For full details see the [3.0 release announcement](3.0-announcement.md). --- -For older release notes, [please see the version 2.x documentation](old-release-notes). +For older release notes, [please see the version 2.x documentation][old-release-notes]. [cite]: http://www.catb.org/~esr/writings/cathedral-bazaar/cathedral-bazaar/ar01s04.html [deprecation-policy]: #deprecation-policy @@ -149,13 +214,17 @@ For older release notes, [please see the version 2.x documentation](old-release- [2.1.0-notes]: https://groups.google.com/d/topic/django-rest-framework/Vv2M0CMY9bg/discussion [ticket-582]: https://github.com/tomchristie/django-rest-framework/issues/582 [rfc-6266]: http://tools.ietf.org/html/rfc6266#section-4.3 -[old-release-notes]: http://tomchristie.github.io/rest-framework-2-docs/topics/release-notes#24x-series +[old-release-notes]: https://github.com/tomchristie/django-rest-framework/blob/version-2.4.x/docs/topics/release-notes.md [3.0.1-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.0.1+Release%22 [3.0.2-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.0.2+Release%22 [3.0.3-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.0.3+Release%22 [3.0.4-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.0.4+Release%22 [3.0.5-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.0.5+Release%22 +[3.1.0-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.1.0+Release%22 +[3.1.1-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.1.1+Release%22 +[3.1.2-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.1.2+Release%22 +[3.1.3-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.1.3+Release%22 [gh2013]: https://github.com/tomchristie/django-rest-framework/issues/2013 @@ -254,3 +323,62 @@ For older release notes, [please see the version 2.x documentation](old-release- [gh2519]: https://github.com/tomchristie/django-rest-framework/issues/2519 [gh2524]: https://github.com/tomchristie/django-rest-framework/issues/2524 [gh2530]: https://github.com/tomchristie/django-rest-framework/issues/2530 + +[gh2691]: https://github.com/tomchristie/django-rest-framework/issues/2691 +[gh2685]: https://github.com/tomchristie/django-rest-framework/issues/2685 +[gh2591]: https://github.com/tomchristie/django-rest-framework/issues/2591 +[gh2678]: https://github.com/tomchristie/django-rest-framework/issues/2678 +[gh2667]: https://github.com/tomchristie/django-rest-framework/issues/2667 +[gh2700]: https://github.com/tomchristie/django-rest-framework/issues/2700 +[gh2645]: https://github.com/tomchristie/django-rest-framework/issues/2645 +[gh2640]: https://github.com/tomchristie/django-rest-framework/issues/2640 +[gh2637]: https://github.com/tomchristie/django-rest-framework/issues/2637 +[gh2641]: https://github.com/tomchristie/django-rest-framework/issues/2641 +[gh2631]: https://github.com/tomchristie/django-rest-framework/issues/2631 +[gh2741]: https://github.com/tomchristie/django-rest-framework/issues/2641 +[gh2743]: https://github.com/tomchristie/django-rest-framework/issues/2643 + +[gh2656]: https://github.com/tomchristie/django-rest-framework/issues/2656 +[gh2687]: https://github.com/tomchristie/django-rest-framework/issues/2687 +[gh2869]: https://github.com/tomchristie/django-rest-framework/issues/2869 +[gh2764]: https://github.com/tomchristie/django-rest-framework/issues/2764 +[gh2763]: https://github.com/tomchristie/django-rest-framework/issues/2763 +[gh2757]: https://github.com/tomchristie/django-rest-framework/issues/2757 +[gh2630]: https://github.com/tomchristie/django-rest-framework/issues/2630 +[gh2724]: https://github.com/tomchristie/django-rest-framework/issues/2724 +[gh2711]: https://github.com/tomchristie/django-rest-framework/issues/2711 +[gh2745]: https://github.com/tomchristie/django-rest-framework/issues/2745 +[gh2754]: https://github.com/tomchristie/django-rest-framework/issues/2754 +[gh2762]: https://github.com/tomchristie/django-rest-framework/issues/2762 +[gh2798]: https://github.com/tomchristie/django-rest-framework/issues/2798 +[gh2807]: https://github.com/tomchristie/django-rest-framework/issues/2807 +[gh2818]: https://github.com/tomchristie/django-rest-framework/issues/2818 +[gh2835]: https://github.com/tomchristie/django-rest-framework/issues/2835 +[gh2836]: https://github.com/tomchristie/django-rest-framework/issues/2836 +[gh2853]: https://github.com/tomchristie/django-rest-framework/issues/2853 +[gh2862]: https://github.com/tomchristie/django-rest-framework/issues/2862 +[gh2863]: https://github.com/tomchristie/django-rest-framework/issues/2863 +[gh2868]: https://github.com/tomchristie/django-rest-framework/issues/2868 +[gh2905]: https://github.com/tomchristie/django-rest-framework/issues/2905 + +[gh2481]: https://github.com/tomchristie/django-rest-framework/issues/2481 +[gh2989]: https://github.com/tomchristie/django-rest-framework/issues/2989 +[gh2788]: https://github.com/tomchristie/django-rest-framework/issues/2788 +[gh3000]: https://github.com/tomchristie/django-rest-framework/issues/3000 +[gh2993]: https://github.com/tomchristie/django-rest-framework/issues/2993 +[gh2894]: https://github.com/tomchristie/django-rest-framework/issues/2894 +[gh2981]: https://github.com/tomchristie/django-rest-framework/issues/2981 +[gh2811]: https://github.com/tomchristie/django-rest-framework/issues/2811 +[gh2975]: https://github.com/tomchristie/django-rest-framework/issues/2975 +[gh2839]: https://github.com/tomchristie/django-rest-framework/issues/2839 +[gh2940]: https://github.com/tomchristie/django-rest-framework/issues/2940 +[gh2887]: https://github.com/tomchristie/django-rest-framework/issues/2887 +[gh2034]: https://github.com/tomchristie/django-rest-framework/issues/2034 +[gh2933]: https://github.com/tomchristie/django-rest-framework/issues/2933 +[gh2948]: https://github.com/tomchristie/django-rest-framework/issues/2948 +[gh2947]: https://github.com/tomchristie/django-rest-framework/issues/2947 +[gh2952]: https://github.com/tomchristie/django-rest-framework/issues/2952 +[gh2747]: https://github.com/tomchristie/django-rest-framework/issues/2747 +[gh2618]: https://github.com/tomchristie/django-rest-framework/issues/2618 +[gh3008]: https://github.com/tomchristie/django-rest-framework/issues/3008 +[gh2695]: https://github.com/tomchristie/django-rest-framework/issues/2695 diff --git a/docs/topics/rest-hypermedia-hateoas.md b/docs/topics/rest-hypermedia-hateoas.md index 7e6d24081..5517b150c 100644 --- a/docs/topics/rest-hypermedia-hateoas.md +++ b/docs/topics/rest-hypermedia-hateoas.md @@ -32,7 +32,7 @@ REST framework also includes [serialization] and [parser]/[renderer] components ## What REST framework doesn't provide. -What REST framework doesn't do is give you is machine readable hypermedia formats such as [HAL][hal], [Collection+JSON][collection], [JSON API][json-api] or HTML [microformats] by default, or the ability to auto-magically create fully HATEOAS style APIs that include hypermedia-based form descriptions and semantically labelled hyperlinks. Doing so would involve making opinionated choices about API design that should really remain outside of the framework's scope. +What REST framework doesn't do is give you machine readable hypermedia formats such as [HAL][hal], [Collection+JSON][collection], [JSON API][json-api] or HTML [microformats] by default, or the ability to auto-magically create fully HATEOAS style APIs that include hypermedia-based form descriptions and semantically labelled hyperlinks. Doing so would involve making opinionated choices about API design that should really remain outside of the framework's scope. [cite]: http://vimeo.com/channels/restfest/page:2 [dissertation]: http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm diff --git a/docs/topics/third-party-resources.md b/docs/topics/third-party-resources.md index 2f46e1fc4..ae2ae3bc6 100644 --- a/docs/topics/third-party-resources.md +++ b/docs/topics/third-party-resources.md @@ -206,10 +206,12 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque * [drf-compound-fields][drf-compound-fields] - Provides "compound" serializer fields, such as lists of simple values. * [django-extra-fields][django-extra-fields] - Provides extra serializer fields. +* [django-versatileimagefield][django-versatileimagefield] - Provides a drop-in replacement for Django's stock `ImageField` that makes it easy to serve images in multiple sizes/renditions from a single field. For DRF-specific implementation docs, [click here][django-versatileimagefield-drf-docs]. ### Views * [djangorestframework-bulk][djangorestframework-bulk] - Implements generic view mixins as well as some common concrete generic views to allow to apply bulk operations via API requests. +* [django-rest-multiple-models][django-rest-multiple-models] - Provides a generic view (and mixin) for sending multiple serialized models and/or querysets via a single API request. ### Routers @@ -236,9 +238,12 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque * [djangorestrelationalhyperlink][djangorestrelationalhyperlink] - A hyperlinked serialiser that can can be used to alter relationships via hyperlinks, but otherwise like a hyperlink model serializer. * [django-rest-swagger][django-rest-swagger] - An API documentation generator for Swagger UI. * [django-rest-framework-proxy][django-rest-framework-proxy] - Proxy to redirect incoming request to another API server. -* [gaiarestframework][gaiarestframework] - Utils for django-rest-framewok +* [gaiarestframework][gaiarestframework] - Utils for django-rest-framework * [drf-extensions][drf-extensions] - A collection of custom extensions * [ember-django-adapter][ember-django-adapter] - An adapter for working with Ember.js +* [django-versatileimagefield][django-versatileimagefield] - Provides a drop-in replacement for Django's stock `ImageField` that makes it easy to serve images in multiple sizes/renditions from a single field. For DRF-specific implementation docs, [click here][django-versatileimagefield-drf-docs]. +* [drf-tracking][drf-tracking] - Utilities to track requests to DRF API views. +* [django-rest-framework-braces][django-rest-framework-braces] - Collection of utilities for working with Django Rest Framework. The most notable ones are [FormSerializer](https://django-rest-framework-braces.readthedocs.org/en/latest/overview.html#formserializer) and [SerializerForm](https://django-rest-framework-braces.readthedocs.org/en/latest/overview.html#serializerform), which are adapters between DRF serializers and Django forms. ## Other Resources @@ -265,6 +270,9 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque * [Web API performance: profiling Django REST framework][web-api-performance-profiling-django-rest-framework] * [API Development with Django and Django REST Framework][api-development-with-django-and-django-rest-framework] +### Documentations +* [Classy Django REST Framework][cdrf.co] + [cite]: http://www.software-ecosystems.com/Software_Ecosystems/Ecosystems.html [cookiecutter]: https://github.com/jpadilla/cookiecutter-django-rest-framework [new-repo]: https://github.com/new @@ -297,6 +305,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque [drf-compound-fields]: https://github.com/estebistec/drf-compound-fields [django-extra-fields]: https://github.com/Hipo/drf-extra-fields [djangorestframework-bulk]: https://github.com/miki725/django-rest-framework-bulk +[django-rest-multiple-models]: https://github.com/Axiologue/DjangoRestMultipleModels [drf-nested-routers]: https://github.com/alanjds/drf-nested-routers [wq.db.rest]: http://wq.io/docs/about-rest [djangorestframework-msgpack]: https://github.com/juanriaza/django-rest-framework-msgpack @@ -326,3 +335,8 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque [web-api-performance-profiling-django-rest-framework]: http://dabapps.com/blog/api-performance-profiling-django-rest-framework/ [api-development-with-django-and-django-rest-framework]: https://bnotions.com/api-development-with-django-and-django-rest-framework/ [django-rest-auth]: https://github.com/Tivix/django-rest-auth/ +[django-versatileimagefield]: https://github.com/WGBH/django-versatileimagefield +[django-versatileimagefield-drf-docs]:http://django-versatileimagefield.readthedocs.org/en/latest/drf_integration.html +[cdrf.co]:http://www.cdrf.co +[drf-tracking]: https://github.com/aschn/drf-tracking +[django-rest-framework-braces]: https://github.com/dealertrack/django-rest-framework-braces diff --git a/docs/topics/writable-nested-serializers.md b/docs/topics/writable-nested-serializers.md index ed614bd24..cab700e5b 100644 --- a/docs/topics/writable-nested-serializers.md +++ b/docs/topics/writable-nested-serializers.md @@ -28,11 +28,11 @@ Some example output from our serializer. { 'title': 'Leaving party preperations', - 'items': { + 'items': [ {'text': 'Compile playlist', 'is_completed': True}, {'text': 'Send invites', 'is_completed': False}, {'text': 'Clean house', 'is_completed': False} - } + ] } Let's take a look at updating our nested one-to-many data structure. diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md index ceb23a020..8a7a8dc07 100644 --- a/docs/tutorial/1-serialization.md +++ b/docs/tutorial/1-serialization.md @@ -89,7 +89,6 @@ We'll also need to create an initial migration for our snippet model, and sync t The first thing we need to get started on our Web API is to provide a way of serializing and deserializing the snippet instances into representations such as `json`. We can do this by declaring serializers that work very similar to Django's forms. Create a file in the `snippets` directory named `serializers.py` and add the following. - from django.forms import widgets from rest_framework import serializers from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES @@ -124,7 +123,7 @@ The first part of the serializer class defines the fields that get serialized/de A serializer class is very similar to a Django `Form` class, and includes similar validation flags on the various fields, such as `required`, `max_length` and `default`. -The field flags can also control how the serializer should be displayed in certain circumstances, such as when rendering to HTML. The `{'base_template': 'textarea.html'}` flag above is equivelent to using `widget=widgets.Textarea` on a Django `Form` class. This is particularly useful for controlling how the browsable API should be displayed, as we'll see later in the tutorial. +The field flags can also control how the serializer should be displayed in certain circumstances, such as when rendering to HTML. The `{'base_template': 'textarea.html'}` flag above is equivalent to using `widget=widgets.Textarea` on a Django `Form` class. This is particularly useful for controlling how the browsable API should be displayed, as we'll see later in the tutorial. We can actually also save ourselves some time by using the `ModelSerializer` class, as we'll see later, but for now we'll keep our serializer definition explicit. diff --git a/docs/tutorial/2-requests-and-responses.md b/docs/tutorial/2-requests-and-responses.md index e2c173d6e..51cea4f1b 100644 --- a/docs/tutorial/2-requests-and-responses.md +++ b/docs/tutorial/2-requests-and-responses.md @@ -108,7 +108,7 @@ and Now update the `urls.py` file slightly, to append a set of `format_suffix_patterns` in addition to the existing URLs. - from django.conf.urls import patterns, url + from django.conf.urls import url from rest_framework.urlpatterns import format_suffix_patterns from snippets import views @@ -200,7 +200,7 @@ See the [browsable api][browsable-api] topic for more information about the brow In [tutorial part 3][tut-3], we'll start using class based views, and see how generic views reduce the amount of code we need to write. -[json-url]: http://example.com/api/items/4.json +[json-url]: http://example.com/api/items/4/.json [devserver]: http://127.0.0.1:8000/snippets/ [browsable-api]: ../topics/browsable-api.md [tut-1]: 1-serialization.md diff --git a/docs/tutorial/5-relationships-and-hyperlinked-apis.md b/docs/tutorial/5-relationships-and-hyperlinked-apis.md index 740a4ce21..feef1fcf0 100644 --- a/docs/tutorial/5-relationships-and-hyperlinked-apis.md +++ b/docs/tutorial/5-relationships-and-hyperlinked-apis.md @@ -18,7 +18,7 @@ Right now we have endpoints for 'snippets' and 'users', but we don't have a sing 'snippets': reverse('snippet-list', request=request, format=format) }) -Notice that we're using REST framework's `reverse` function in order to return fully-qualified URLs. +Two things should be noticed here. First, we're using REST framework's `reverse` function in order to return fully-qualified URLs; second, URL patterns are identified by convenience names that we will declare later on in our `snippets/urls.py`. ## Creating an endpoint for the highlighted snippets @@ -104,9 +104,11 @@ If we're going to have a hyperlinked API, we need to make sure we name our URL p * Our user serializer includes a field that refers to `'snippet-detail'`. * Our snippet and user serializers include `'url'` fields that by default will refer to `'{model_name}-detail'`, which in this case will be `'snippet-detail'` and `'user-detail'`. -After adding all those names into our URLconf, our final `snippets/urls.py` file should look something like this: +After adding all those names into our URLconf, our final `snippets/urls.py` file should look like this: from django.conf.urls import url, include + from rest_framework.urlpatterns import format_suffix_patterns + from snippets import views # API endpoints urlpatterns = format_suffix_patterns([ @@ -141,7 +143,7 @@ The list views for users and code snippets could end up returning quite a lot of We can change the default list style to use pagination, by modifying our `tutorial/settings.py` file slightly. Add the following setting: REST_FRAMEWORK = { - 'PAGINATE_BY': 10 + 'PAGE_SIZE': 10 } Note that settings in REST framework are all namespaced into a single dictionary setting, named 'REST_FRAMEWORK', which helps keep them well separated from your other project settings. diff --git a/docs/tutorial/quickstart.md b/docs/tutorial/quickstart.md index a4474c34e..5feacf4c9 100644 --- a/docs/tutorial/quickstart.md +++ b/docs/tutorial/quickstart.md @@ -83,8 +83,6 @@ Rather than write multiple views we're grouping together all the common behavior We can easily break these down into individual views if we need to, but using viewsets keeps the view logic nicely organized as well as being very concise. -Notice that our viewset classes here are a little different from those in the [frontpage example][readme-example-api], as they include `queryset` and `serializer_class` attributes, instead of a `model` attribute. - For trivial cases you can simply set a `model` attribute on the `ViewSet` class and the serializer and queryset will be automatically generated for you. Setting the `queryset` and/or `serializer_class` attributes gives you more explicit control of the API behaviour, and is the recommended style for most applications. ## URLs @@ -123,7 +121,7 @@ We'd also like to set a few global settings. We'd like to turn on pagination, a REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAdminUser',), - 'PAGINATE_BY': 10 + 'PAGE_SIZE': 10 } Okay, we're done. diff --git a/docs_theme/404.html b/docs_theme/404.html index 44993e37d..ce520a7c1 100644 --- a/docs_theme/404.html +++ b/docs_theme/404.html @@ -1,216 +1,9 @@ - - +{% extends "base.html" %} - - - - Django REST framework - 404 - Page not found - - - - - +{% block content %} - - - - - +

404

+

Page not found

+

Try the homepage, or search the documentation.

- - - - - - - - -
- - - -
-
- - - -
-
-

404

-

Page not found -

-

Try the homepage, or search the documentation.

-
- -
- -
- -
- - -
-
- - - - - - - - - - - - - +{% endblock %} diff --git a/docs_theme/base.html b/docs_theme/base.html index b3066eb31..4e95f1f95 100644 --- a/docs_theme/base.html +++ b/docs_theme/base.html @@ -4,11 +4,11 @@ - {{ page_title }} + {% if page_title %}{{ page_title }} - {% endif %}{{ site_name }} - + @@ -54,37 +54,27 @@ } - +
- {% include "nav.html" %}
- - - + {{ content }} + {% endblock %} + +
+
+
+
- - +