Merge remote-tracking branch 'upstream/master'
35
.travis.yml
|
@ -5,40 +5,39 @@ python:
|
||||||
- "2.7"
|
- "2.7"
|
||||||
- "3.2"
|
- "3.2"
|
||||||
- "3.3"
|
- "3.3"
|
||||||
|
- "3.4"
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- DJANGO="https://www.djangoproject.com/download/1.7a2/tarball/"
|
- DJANGO="https://www.djangoproject.com/download/1.7c2/tarball/"
|
||||||
- DJANGO="django==1.6.2"
|
- DJANGO="django==1.6.5"
|
||||||
- DJANGO="django==1.5.5"
|
- DJANGO="django==1.5.8"
|
||||||
- DJANGO="django==1.4.10"
|
- DJANGO="django==1.4.13"
|
||||||
- DJANGO="django==1.3.7"
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- pip install $DJANGO
|
- pip install $DJANGO
|
||||||
- pip install defusedxml==0.3 Pillow==2.3.0
|
- pip install defusedxml==0.3
|
||||||
|
- pip install Pillow==2.3.0
|
||||||
|
- pip install django-guardian==1.2.3
|
||||||
|
- pip install pytest-django==2.6.1
|
||||||
|
- pip install flake8==2.2.2
|
||||||
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install oauth2==1.5.211; fi"
|
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install oauth2==1.5.211; fi"
|
||||||
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-oauth-plus==2.2.4; fi"
|
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-oauth-plus==2.2.4; fi"
|
||||||
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-oauth2-provider==0.2.4; fi"
|
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-oauth2-provider==0.2.4; fi"
|
||||||
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-guardian==1.1.1; fi"
|
|
||||||
- "if [[ ${DJANGO::11} == 'django==1.3' ]]; then pip install django-filter==0.5.4; fi"
|
- "if [[ ${DJANGO::11} == 'django==1.3' ]]; then pip install django-filter==0.5.4; fi"
|
||||||
- "if [[ ${DJANGO::11} != 'django==1.3' ]]; then pip install django-filter==0.7; fi"
|
- "if [[ ${DJANGO::11} != 'django==1.3' ]]; then pip install django-filter==0.7; fi"
|
||||||
- "if [[ ${TRAVIS_PYTHON_VERSION::1} == '3' ]]; then pip install -e git+https://github.com/linovia/django-guardian.git@feature/django_1_7#egg=django-guardian-1.2.0; fi"
|
- "if [[ ${DJANGO} == 'https://www.djangoproject.com/download/1.7c2/tarball/' ]]; then pip install -e git+https://github.com/linovia/django-guardian.git@feature/django_1_7#egg=django-guardian-1.2.0; fi"
|
||||||
- "if [[ ${DJANGO} == 'https://www.djangoproject.com/download/1.7a2/tarball/' ]]; then pip install -e git+https://github.com/linovia/django-guardian.git@feature/django_1_7#egg=django-guardian-1.2.0; fi"
|
|
||||||
- export PYTHONPATH=.
|
- export PYTHONPATH=.
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- python rest_framework/runtests/runtests.py
|
- ./runtests.py
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
exclude:
|
exclude:
|
||||||
- python: "2.6"
|
- python: "2.6"
|
||||||
env: DJANGO="https://www.djangoproject.com/download/1.7a2/tarball/"
|
env: DJANGO="https://www.djangoproject.com/download/1.7c2/tarball/"
|
||||||
- python: "3.2"
|
- python: "3.2"
|
||||||
env: DJANGO="django==1.4.10"
|
env: DJANGO="django==1.4.13"
|
||||||
- python: "3.2"
|
|
||||||
env: DJANGO="django==1.3.7"
|
|
||||||
- python: "3.3"
|
- python: "3.3"
|
||||||
env: DJANGO="django==1.4.10"
|
env: DJANGO="django==1.4.13"
|
||||||
- python: "3.3"
|
- python: "3.4"
|
||||||
env: DJANGO="django==1.3.7"
|
env: DJANGO="django==1.4.13"
|
||||||
|
|
||||||
|
|
|
@ -62,10 +62,10 @@ To run the tests, clone the repository, and then:
|
||||||
virtualenv env
|
virtualenv env
|
||||||
env/bin/activate
|
env/bin/activate
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
pip install -r optionals.txt
|
pip install -r requirements-test.txt
|
||||||
|
|
||||||
# Run the tests
|
# Run the tests
|
||||||
rest_framework/runtests/runtests.py
|
./runtests.py
|
||||||
|
|
||||||
You can also use the excellent [`tox`][tox] testing tool to run the tests against all supported versions of Python and Django. Install `tox` globally, and then simply run:
|
You can also use the excellent [`tox`][tox] testing tool to run the tests against all supported versions of Python and Django. Install `tox` globally, and then simply run:
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
recursive-include rest_framework/static *.js *.css *.png
|
recursive-include rest_framework/static *.js *.css *.png
|
||||||
recursive-include rest_framework/templates *.html
|
recursive-include rest_framework/templates *.html
|
||||||
|
recursive-exclude * __pycache__
|
||||||
|
recursive-exclude * *.py[co]
|
||||||
|
|
77
README.md
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
# Overview
|
# Overview
|
||||||
|
|
||||||
Django REST framework is a powerful and flexible toolkit that makes it easy to build Web APIs.
|
Django REST framework is a powerful and flexible toolkit for building Web APIs.
|
||||||
|
|
||||||
Some reasons you might want to use REST framework:
|
Some reasons you might want to use REST framework:
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ There is a live example API for testing purposes, [available here][sandbox].
|
||||||
# Requirements
|
# Requirements
|
||||||
|
|
||||||
* Python (2.6.5+, 2.7, 3.2, 3.3)
|
* Python (2.6.5+, 2.7, 3.2, 3.3)
|
||||||
* Django (1.3, 1.4, 1.5, 1.6)
|
* Django (1.4.2+, 1.5, 1.6, 1.7)
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
|
@ -46,33 +46,44 @@ Add `'rest_framework'` to your `INSTALLED_APPS` setting.
|
||||||
|
|
||||||
Let's take a look at a quick example of using REST framework to build a simple model-backed API for accessing users and groups.
|
Let's take a look at a quick example of using REST framework to build a simple model-backed API for accessing users and groups.
|
||||||
|
|
||||||
Here's our project's root `urls.py` module:
|
Startup up a new project like so...
|
||||||
|
|
||||||
|
pip install django
|
||||||
|
pip install djangorestframework
|
||||||
|
django-admin.py startproject example .
|
||||||
|
./manage.py syncdb
|
||||||
|
|
||||||
|
Now edit the `example/urls.py` module in your project:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from django.conf.urls.defaults import url, patterns, include
|
from django.conf.urls import url, include
|
||||||
from django.contrib.auth.models import User, Group
|
from django.contrib.auth.models import User
|
||||||
from rest_framework import viewsets, routers
|
from rest_framework import serializers, viewsets, routers
|
||||||
|
|
||||||
|
# Serializers define the API representation.
|
||||||
|
class UserSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = ('url', 'username', 'email', 'is_staff')
|
||||||
|
|
||||||
|
|
||||||
# ViewSets define the view behavior.
|
# ViewSets define the view behavior.
|
||||||
class UserViewSet(viewsets.ModelViewSet):
|
class UserViewSet(viewsets.ModelViewSet):
|
||||||
model = User
|
queryset = User.objects.all()
|
||||||
|
serializer_class = UserSerializer
|
||||||
class GroupViewSet(viewsets.ModelViewSet):
|
|
||||||
model = Group
|
|
||||||
|
|
||||||
|
|
||||||
# Routers provide an easy way of automatically determining the URL conf
|
# Routers provide a way of automatically determining the URL conf.
|
||||||
router = routers.DefaultRouter()
|
router = routers.DefaultRouter()
|
||||||
router.register(r'users', UserViewSet)
|
router.register(r'users', UserViewSet)
|
||||||
router.register(r'groups', GroupViewSet)
|
|
||||||
|
|
||||||
|
|
||||||
# Wire up our API using automatic URL routing.
|
# Wire up our API using automatic URL routing.
|
||||||
# Additionally, we include login URLs for the browseable API.
|
# Additionally, we include login URLs for the browseable API.
|
||||||
urlpatterns = patterns('',
|
urlpatterns = [
|
||||||
url(r'^', include(router.urls)),
|
url(r'^', include(router.urls)),
|
||||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
||||||
)
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
We'd also like to configure a couple of settings for our API.
|
We'd also like to configure a couple of settings for our API.
|
||||||
|
@ -80,12 +91,12 @@ We'd also like to configure a couple of settings for our API.
|
||||||
Add the following to your `settings.py` module:
|
Add the following to your `settings.py` module:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
REST_FRAMEWORK = {
|
INSTALLED_APPS = (
|
||||||
# Use hyperlinked styles by default.
|
... # Make sure to include the default installed apps here.
|
||||||
# Only used if the `serializer_class` attribute is not set on a view.
|
'rest_framework',
|
||||||
'DEFAULT_MODEL_SERIALIZER_CLASS':
|
)
|
||||||
'rest_framework.serializers.HyperlinkedModelSerializer',
|
|
||||||
|
|
||||||
|
REST_FRAMEWORK = {
|
||||||
# Use Django's standard `django.contrib.auth` permissions,
|
# Use Django's standard `django.contrib.auth` permissions,
|
||||||
# or allow read-only access for unauthenticated users.
|
# or allow read-only access for unauthenticated users.
|
||||||
'DEFAULT_PERMISSION_CLASSES': [
|
'DEFAULT_PERMISSION_CLASSES': [
|
||||||
|
@ -93,10 +104,35 @@ REST_FRAMEWORK = {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Don't forget to make sure you've also added `rest_framework` to your `INSTALLED_APPS` setting.
|
|
||||||
|
|
||||||
That's it, we're done!
|
That's it, we're done!
|
||||||
|
|
||||||
|
./manage.py runserver
|
||||||
|
|
||||||
|
You can now open the API in your browser at `http://127.0.0.1:8000/`, and view your new 'users' API. If you use the `Login` control in the top right corner you'll also be able to add, create and delete users from the system.
|
||||||
|
|
||||||
|
You can also interact with the API using command line tools such as [`curl`](http://curl.haxx.se/). For example, to list the users endpoint:
|
||||||
|
|
||||||
|
$ curl -H 'Accept: application/json; indent=4' -u admin:password http://127.0.0.1:8000/users/
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"url": "http://127.0.0.1:8000/users/1/",
|
||||||
|
"username": "admin",
|
||||||
|
"email": "admin@example.com",
|
||||||
|
"is_staff": true,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Or to create a new user:
|
||||||
|
|
||||||
|
$ curl -X POST -d username=new -d email=new@example.com -d is_staff=false -H 'Accept: application/json; indent=4' -u admin:password http://127.0.0.1:8000/users/
|
||||||
|
{
|
||||||
|
"url": "http://127.0.0.1:8000/users/2/",
|
||||||
|
"username": "new",
|
||||||
|
"email": "new@example.com",
|
||||||
|
"is_staff": false,
|
||||||
|
}
|
||||||
|
|
||||||
# Documentation & Support
|
# Documentation & Support
|
||||||
|
|
||||||
Full documentation for the project is available at [http://www.django-rest-framework.org][docs].
|
Full documentation for the project is available at [http://www.django-rest-framework.org][docs].
|
||||||
|
@ -136,6 +172,7 @@ 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
|
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.
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
[build-status-image]: https://secure.travis-ci.org/tomchristie/django-rest-framework.png?branch=master
|
[build-status-image]: https://secure.travis-ci.org/tomchristie/django-rest-framework.png?branch=master
|
||||||
[travis]: http://travis-ci.org/tomchristie/django-rest-framework?branch=master
|
[travis]: http://travis-ci.org/tomchristie/django-rest-framework?branch=master
|
||||||
[twitter]: https://twitter.com/_tomchristie
|
[twitter]: https://twitter.com/_tomchristie
|
||||||
|
|
|
@ -119,14 +119,20 @@ Unauthenticated responses that are denied permission will result in an `HTTP 401
|
||||||
|
|
||||||
This authentication scheme uses a simple token-based HTTP Authentication scheme. Token authentication is appropriate for client-server setups, such as native desktop and mobile clients.
|
This authentication scheme uses a simple token-based HTTP Authentication scheme. Token authentication is appropriate for client-server setups, such as native desktop and mobile clients.
|
||||||
|
|
||||||
To use the `TokenAuthentication` scheme, include `rest_framework.authtoken` in your `INSTALLED_APPS` setting:
|
To use the `TokenAuthentication` scheme you'll need to [configure the authentication classes](#setting-the-authentication-scheme) to include `TokenAuthentication`, and additionally include `rest_framework.authtoken` in your `INSTALLED_APPS` setting:
|
||||||
|
|
||||||
INSTALLED_APPS = (
|
INSTALLED_APPS = (
|
||||||
...
|
...
|
||||||
'rest_framework.authtoken'
|
'rest_framework.authtoken'
|
||||||
)
|
)
|
||||||
|
|
||||||
Make sure to run `manage.py syncdb` after changing your settings. The `authtoken` database tables are managed by south (see [Schema migrations](#schema-migrations) below).
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Note:** Make sure to run `manage.py syncdb` after changing your settings. The `rest_framework.authtoken` app provides both Django (from v1.7) and South database migrations. See [Schema migrations](#schema-migrations) below.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
You'll also need to create tokens for your users.
|
You'll also need to create tokens for your users.
|
||||||
|
|
||||||
|
@ -198,7 +204,14 @@ Note that the default `obtain_auth_token` view explicitly uses JSON requests and
|
||||||
|
|
||||||
#### Schema migrations
|
#### Schema migrations
|
||||||
|
|
||||||
The `rest_framework.authtoken` app includes a south migration that will create the authtoken table.
|
The `rest_framework.authtoken` app includes both Django native migrations (for Django versions >1.7) and South migrations (for Django versions <1.7) that will create the authtoken table.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
**Note**: From REST Framework v2.4.0 using South with Django <1.7 requires upgrading South v1.0+
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
If you're using a [custom user model][custom-user-model] you'll need to make sure that any initial migration that creates the user table runs before the authtoken table is created.
|
If you're using a [custom user model][custom-user-model] you'll need to make sure that any initial migration that creates the user table runs before the authtoken table is created.
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ A dictionary of error codes to error messages.
|
||||||
### `widget`
|
### `widget`
|
||||||
|
|
||||||
Used only if rendering the field to HTML.
|
Used only if rendering the field to HTML.
|
||||||
This argument sets the widget that should be used to render the field.
|
This argument sets the widget that should be used to render the field. For more details, and a list of available widgets, see [the Django documentation on form widgets][django-widgets].
|
||||||
|
|
||||||
### `label`
|
### `label`
|
||||||
|
|
||||||
|
@ -164,11 +164,12 @@ Corresponds to `django.db.models.fields.BooleanField`.
|
||||||
## CharField
|
## CharField
|
||||||
|
|
||||||
A text representation, optionally validates the text to be shorter than `max_length` and longer than `min_length`.
|
A text representation, optionally validates the text to be shorter than `max_length` and longer than `min_length`.
|
||||||
|
If `allow_none` is `False` (default), `None` values will be converted to an empty string.
|
||||||
|
|
||||||
Corresponds to `django.db.models.fields.CharField`
|
Corresponds to `django.db.models.fields.CharField`
|
||||||
or `django.db.models.fields.TextField`.
|
or `django.db.models.fields.TextField`.
|
||||||
|
|
||||||
**Signature:** `CharField(max_length=None, min_length=None)`
|
**Signature:** `CharField(max_length=None, min_length=None, allow_none=False)`
|
||||||
|
|
||||||
## URLField
|
## URLField
|
||||||
|
|
||||||
|
@ -184,7 +185,9 @@ Corresponds to `django.db.models.fields.SlugField`.
|
||||||
|
|
||||||
## ChoiceField
|
## ChoiceField
|
||||||
|
|
||||||
A field that can accept a value out of a limited set of choices.
|
A field that can accept a value out of a limited set of choices. Optionally takes a `blank_display_value` parameter that customizes the display value of an empty choice.
|
||||||
|
|
||||||
|
**Signature:** `ChoiceField(choices=(), blank_display_value=None)`
|
||||||
|
|
||||||
## EmailField
|
## EmailField
|
||||||
|
|
||||||
|
@ -345,7 +348,7 @@ As an example, let's create a field that can be used represent the class name of
|
||||||
"""
|
"""
|
||||||
Serialize the object's class name.
|
Serialize the object's class name.
|
||||||
"""
|
"""
|
||||||
return obj.__class__
|
return obj.__class__.__name__
|
||||||
|
|
||||||
# Third party packages
|
# Third party packages
|
||||||
|
|
||||||
|
@ -355,9 +358,26 @@ The following third party packages are also available.
|
||||||
|
|
||||||
The [drf-compound-fields][drf-compound-fields] package provides "compound" serializer fields, such as lists of simple values, which can be described by other fields rather than serializers with the `many=True` option. Also provided are fields for typed dictionaries and values that can be either a specific type or a list of items of that type.
|
The [drf-compound-fields][drf-compound-fields] package provides "compound" serializer fields, such as lists of simple values, which can be described by other fields rather than serializers with the `many=True` option. Also provided are fields for typed dictionaries and values that can be either a specific type or a list of items of that type.
|
||||||
|
|
||||||
|
## DRF Extra Fields
|
||||||
|
|
||||||
|
The [drf-extra-fields][drf-extra-fields] package provides extra serializer fields for REST framework, including `Base64ImageField` and `PointField` classes.
|
||||||
|
|
||||||
|
## django-rest-framework-gis
|
||||||
|
|
||||||
|
The [django-rest-framework-gis][django-rest-framework-gis] package provides geographic addons for django rest framework like a `GeometryField` field and a GeoJSON serializer.
|
||||||
|
|
||||||
|
## django-rest-framework-hstore
|
||||||
|
|
||||||
|
The [django-rest-framework-hstore][django-rest-framework-hstore] package provides an `HStoreField` to support [django-hstore][django-hstore] `DictionaryField` model field.
|
||||||
|
|
||||||
[cite]: https://docs.djangoproject.com/en/dev/ref/forms/api/#django.forms.Form.cleaned_data
|
[cite]: https://docs.djangoproject.com/en/dev/ref/forms/api/#django.forms.Form.cleaned_data
|
||||||
[FILE_UPLOAD_HANDLERS]: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS
|
[FILE_UPLOAD_HANDLERS]: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS
|
||||||
[ecma262]: http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15
|
[ecma262]: http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15
|
||||||
[strftime]: http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior
|
[strftime]: http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior
|
||||||
|
[django-widgets]: https://docs.djangoproject.com/en/dev/ref/forms/widgets/
|
||||||
[iso8601]: http://www.w3.org/TR/NOTE-datetime
|
[iso8601]: http://www.w3.org/TR/NOTE-datetime
|
||||||
[drf-compound-fields]: http://drf-compound-fields.readthedocs.org
|
[drf-compound-fields]: http://drf-compound-fields.readthedocs.org
|
||||||
|
[drf-extra-fields]: https://github.com/Hipo/drf-extra-fields
|
||||||
|
[django-rest-framework-gis]: https://github.com/djangonauts/django-rest-framework-gis
|
||||||
|
[django-rest-framework-hstore]: https://github.com/djangonauts/django-rest-framework-hstore
|
||||||
|
[django-hstore]: https://github.com/djangonauts/django-hstore
|
||||||
|
|
|
@ -24,7 +24,7 @@ For example:
|
||||||
from myapp.serializers import PurchaseSerializer
|
from myapp.serializers import PurchaseSerializer
|
||||||
from rest_framework import generics
|
from rest_framework import generics
|
||||||
|
|
||||||
class PurchaseList(generics.ListAPIView)
|
class PurchaseList(generics.ListAPIView):
|
||||||
serializer_class = PurchaseSerializer
|
serializer_class = PurchaseSerializer
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
@ -46,7 +46,7 @@ For example if your URL config contained an entry like this:
|
||||||
|
|
||||||
You could then write a view that returned a purchase queryset filtered by the username portion of the URL:
|
You could then write a view that returned a purchase queryset filtered by the username portion of the URL:
|
||||||
|
|
||||||
class PurchaseList(generics.ListAPIView)
|
class PurchaseList(generics.ListAPIView):
|
||||||
serializer_class = PurchaseSerializer
|
serializer_class = PurchaseSerializer
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
@ -63,7 +63,7 @@ A final example of filtering the initial queryset would be to determine the init
|
||||||
|
|
||||||
We can override `.get_queryset()` to deal with URLs such as `http://example.com/api/purchases?username=denvercoder9`, and filter the queryset only if the `username` parameter is included in the URL:
|
We can override `.get_queryset()` to deal with URLs such as `http://example.com/api/purchases?username=denvercoder9`, and filter the queryset only if the `username` parameter is included in the URL:
|
||||||
|
|
||||||
class PurchaseList(generics.ListAPIView)
|
class PurchaseList(generics.ListAPIView):
|
||||||
serializer_class = PurchaseSerializer
|
serializer_class = PurchaseSerializer
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
@ -199,8 +199,7 @@ This enables us to make queries like:
|
||||||
|
|
||||||
http://example.com/api/products?manufacturer__name=foo
|
http://example.com/api/products?manufacturer__name=foo
|
||||||
|
|
||||||
This is nice, but it shows underlying model structure in REST API, which may
|
This is nice, but it exposes the Django's double underscore convention as part of the API. If you instead want to explicitly name the filter argument you can instead explicitly include it on the `FilterSet` class:
|
||||||
be undesired, but you can use:
|
|
||||||
|
|
||||||
import django_filters
|
import django_filters
|
||||||
from myapp.models import Product
|
from myapp.models import Product
|
||||||
|
@ -208,7 +207,6 @@ be undesired, but you can use:
|
||||||
from rest_framework import generics
|
from rest_framework import generics
|
||||||
|
|
||||||
class ProductFilter(django_filters.FilterSet):
|
class ProductFilter(django_filters.FilterSet):
|
||||||
|
|
||||||
manufacturer = django_filters.CharFilter(name="manufacturer__name")
|
manufacturer = django_filters.CharFilter(name="manufacturer__name")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -43,7 +43,13 @@ For more complex cases you might also want to override various methods on the vi
|
||||||
return 20
|
return 20
|
||||||
return 100
|
return 100
|
||||||
|
|
||||||
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 the following entry.
|
def list(self, request):
|
||||||
|
# Note the use of `get_queryset()` instead of `self.queryset`
|
||||||
|
queryset = self.get_queryset()
|
||||||
|
serializer = UserSerializer(queryset, many=True)
|
||||||
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
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(model=User), name='user-list')
|
||||||
|
|
||||||
|
@ -63,15 +69,11 @@ Each of the concrete generic views provided is built by combining `GenericAPIVie
|
||||||
|
|
||||||
The following attributes control the basic view behavior.
|
The following attributes control the basic view behavior.
|
||||||
|
|
||||||
* `queryset` - The queryset that should be used for returning objects from this view. Typically, you must either set this attribute, or override the `get_queryset()` method.
|
* `queryset` - The queryset that should be used for returning objects from this view. Typically, you must either set this attribute, or override the `get_queryset()` method. If you are overriding a view method, it is important that you call `get_queryset()` instead of accessing this property directly, as `queryset` will get evaluated once, and those results will be cached for all subsequent requests.
|
||||||
* `serializer_class` - The serializer class that should be used for validating and deserializing input, and for serializing output. Typically, you must either set this attribute, or override the `get_serializer_class()` method.
|
* `serializer_class` - The serializer class that should be used for validating and deserializing input, and for serializing output. Typically, you must either set this attribute, or override the `get_serializer_class()` method.
|
||||||
* `lookup_field` - The model field that should be used to for performing object lookup of individual model instances. Defaults to `'pk'`. Note that when using hyperlinked APIs you'll need to ensure that *both* the API views *and* the serializer classes set the lookup fields if you need to use a custom value.
|
* `lookup_field` - The model field that should be used to for performing object lookup of individual model instances. Defaults to `'pk'`. Note that when using hyperlinked APIs you'll need to ensure that *both* the API views *and* the serializer classes set the lookup fields if you need to use a custom value.
|
||||||
* `lookup_url_kwarg` - The URL keyword argument that should be used for object lookup. The URL conf should include a keyword argument corresponding to this value. If unset this defaults to using the same value as `lookup_field`.
|
* `lookup_url_kwarg` - The URL keyword argument that should be used for object lookup. The URL conf should include a keyword argument corresponding to this value. If unset this defaults to using the same value as `lookup_field`.
|
||||||
|
|
||||||
**Shortcuts**:
|
|
||||||
|
|
||||||
* `model` - This shortcut may be used instead of setting either (or both) of the `queryset`/`serializer_class` attributes, although using the explicit style is generally preferred. If used instead of `serializer_class`, then then `DEFAULT_MODEL_SERIALIZER_CLASS` setting will determine the base serializer class. Note that `model` is only ever used for generating a default queryset or serializer class - the `queryset` and `serializer_class` attributes are always preferred if provided.
|
|
||||||
|
|
||||||
**Pagination**:
|
**Pagination**:
|
||||||
|
|
||||||
The following attributes are used to control pagination when used with list views.
|
The following attributes are used to control pagination when used with list views.
|
||||||
|
@ -85,6 +87,10 @@ The following attributes are used to control pagination when used with list view
|
||||||
|
|
||||||
* `filter_backends` - A list of filter backend classes that should be used for filtering the queryset. Defaults to the same value as the `DEFAULT_FILTER_BACKENDS` setting.
|
* `filter_backends` - A list of filter backend classes that should be used for filtering the queryset. Defaults to the same value as the `DEFAULT_FILTER_BACKENDS` setting.
|
||||||
|
|
||||||
|
**Deprecated attributes**:
|
||||||
|
|
||||||
|
* `model` - This shortcut may be used instead of setting either (or both) of the `queryset`/`serializer_class` attributes. The explicit style is preferred over the `.model` shortcut, and usage of this attribute is now deprecated.
|
||||||
|
|
||||||
### Methods
|
### Methods
|
||||||
|
|
||||||
**Base methods**:
|
**Base methods**:
|
||||||
|
@ -93,7 +99,9 @@ The following attributes are used to control pagination when used with list view
|
||||||
|
|
||||||
Returns the queryset that should be used for list views, and that should be used as the base for lookups in detail views. Defaults to returning the queryset specified by the `queryset` attribute, or the default queryset for the model if the `model` shortcut is being used.
|
Returns the queryset that should be used for list views, and that should be used as the base for lookups in detail views. Defaults to returning the queryset specified by the `queryset` attribute, or the default queryset for the model if the `model` shortcut is being used.
|
||||||
|
|
||||||
May be overridden to provide dynamic behavior such as returning a queryset that is specific to the user making the request.
|
This method should always be used rather than accessing `self.queryset` directly, as `self.queryset` gets evaluated only once, and those results are cached for all subsequent requests.
|
||||||
|
|
||||||
|
May be overridden to provide dynamic behavior, such as returning a queryset, that is specific to the user making the request.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
@ -105,7 +113,7 @@ For example:
|
||||||
|
|
||||||
Returns an object instance that should be used for detail views. Defaults to using the `lookup_field` parameter to filter the base queryset.
|
Returns an object instance that should be used for detail views. Defaults to using the `lookup_field` parameter to filter the base queryset.
|
||||||
|
|
||||||
May be overridden to provide more complex behavior such as object lookups based on more than one URL kwarg.
|
May be overridden to provide more complex behavior, such as object lookups based on more than one URL kwarg.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
@ -125,7 +133,7 @@ Note that if your API doesn't include any object level permissions, you may opti
|
||||||
|
|
||||||
Returns the classes that should be used to filter the queryset. Defaults to returning the `filter_backends` attribute.
|
Returns the classes that should be used to filter the queryset. Defaults to returning the `filter_backends` attribute.
|
||||||
|
|
||||||
May be override to provide more complex behavior with filters, as using different (or even exlusive) lists of filter_backends depending on different criteria.
|
May be overridden to provide more complex behavior with filters, such as using different (or even exlusive) lists of filter_backends depending on different criteria.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
@ -141,7 +149,7 @@ For example:
|
||||||
|
|
||||||
Returns the class that should be used for the serializer. Defaults to returning the `serializer_class` attribute, or dynamically generating a serializer class if the `model` shortcut is being used.
|
Returns the class that should be used for the serializer. Defaults to returning the `serializer_class` attribute, or dynamically generating a serializer class if the `model` shortcut is being used.
|
||||||
|
|
||||||
May be override to provide dynamic behavior such as using different serializers for read and write operations, or providing different serializers to different types of users.
|
May be overridden to provide dynamic behavior, such as using different serializers for read and write operations, or providing different serializers to different types of users.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
@ -154,7 +162,7 @@ For example:
|
||||||
|
|
||||||
Returns the page size to use with pagination. By default this uses the `paginate_by` attribute, and may be overridden by the client if the `paginate_by_param` attribute is set.
|
Returns the page size to use with pagination. By default this uses the `paginate_by` attribute, and may be overridden by the client if the `paginate_by_param` attribute is set.
|
||||||
|
|
||||||
You may want to override this method to provide more complex behavior such as modifying page sizes based on the media type of the response.
|
You may want to override this method to provide more complex behavior, such as modifying page sizes based on the media type of the response.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
@ -187,7 +195,7 @@ Remember that the `pre_save()` method is not called by `GenericAPIView` itself,
|
||||||
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`.
|
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_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)` - Returns a serializer instance.
|
* `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_pagination_serializer(self, page)` - Returns a serializer instance to use with paginated data.
|
||||||
* `paginate_queryset(self, queryset)` - Paginate a queryset if required, either returning a page object, or `None` if pagination is not configured for this view.
|
* `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.
|
* `filter_queryset(self, queryset)` - Given a queryset, filter it with whichever filter backends are in use, returning a new queryset.
|
||||||
|
@ -196,7 +204,7 @@ You won't typically need to override the following methods, although you might n
|
||||||
|
|
||||||
# Mixins
|
# Mixins
|
||||||
|
|
||||||
The mixin classes provide the actions that are used to provide the basic view behavior. Note that the mixin classes provide action methods rather than defining the handler methods such as `.get()` and `.post()` directly. This allows for more flexible composition of behavior.
|
The mixin classes provide the actions that are used to provide the basic view behavior. Note that the mixin classes provide action methods rather than defining the handler methods, such as `.get()` and `.post()`, directly. This allows for more flexible composition of behavior.
|
||||||
|
|
||||||
## ListModelMixin
|
## ListModelMixin
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,7 @@ You can also set the pagination style on a per-view basis, using the `ListAPIVie
|
||||||
max_paginate_by = 100
|
max_paginate_by = 100
|
||||||
|
|
||||||
Note that using a `paginate_by` value of `None` will turn off pagination for the view.
|
Note that using a `paginate_by` value of `None` will turn off pagination for the view.
|
||||||
|
Note if you use the `PAGINATE_BY_PARAM` settings, you also have to set the `paginate_by_param` attribute in your view to `None` in order to turn off pagination for those requests that contain the `paginate_by_param` parameter.
|
||||||
|
|
||||||
For more complex requirements such as serialization that differs depending on the requested media type you can override the `.get_paginate_by()` and `.get_pagination_serializer_class()` methods.
|
For more complex requirements such as serialization that differs depending on the requested media type you can override the `.get_paginate_by()` and `.get_pagination_serializer_class()` methods.
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,12 @@ For example:
|
||||||
self.check_object_permissions(self.request, obj)
|
self.check_object_permissions(self.request, obj)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
#### Limitations of object level permissions
|
||||||
|
|
||||||
|
For performance reasons the generic views will not automatically apply object level permissions to each instance in a queryset when returning a list of objects.
|
||||||
|
|
||||||
|
Often when you're using object level permissions you'll also want to [filter the queryset][filtering] appropriately, to ensure that users only have visibility onto instances that they are permitted to view.
|
||||||
|
|
||||||
## Setting the permission policy
|
## Setting the permission policy
|
||||||
|
|
||||||
The default permission policy may be set globally, using the `DEFAULT_PERMISSION_CLASSES` setting. For example.
|
The default permission policy may be set globally, using the `DEFAULT_PERMISSION_CLASSES` setting. For example.
|
||||||
|
@ -56,7 +62,7 @@ You can also set the authentication policy on a per-view, or per-viewset basis,
|
||||||
using the `APIView` class based views.
|
using the `APIView` class based views.
|
||||||
|
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.responses import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
class ExampleView(APIView):
|
class ExampleView(APIView):
|
||||||
|
@ -108,7 +114,7 @@ This permission is suitable if you want to your API to allow read permissions to
|
||||||
|
|
||||||
## DjangoModelPermissions
|
## DjangoModelPermissions
|
||||||
|
|
||||||
This permission class ties into Django's standard `django.contrib.auth` [model permissions][contribauth]. When applied to a view that has a `.model` property, authorization will only be granted if the user *is authenticated* and has the *relevant model permissions* assigned.
|
This permission class ties into Django's standard `django.contrib.auth` [model permissions][contribauth]. This permission must only be applied to views that has a `.queryset` property set. Authorization will only be granted if the user *is authenticated* and has the *relevant model permissions* assigned.
|
||||||
|
|
||||||
* `POST` requests require the user to have the `add` permission on the model.
|
* `POST` requests require the user to have the `add` permission on the model.
|
||||||
* `PUT` and `PATCH` requests require the user to have the `change` permission on the model.
|
* `PUT` and `PATCH` requests require the user to have the `change` permission on the model.
|
||||||
|
@ -118,6 +124,12 @@ The default behaviour can also be overridden to support custom model permissions
|
||||||
|
|
||||||
To use custom model permissions, override `DjangoModelPermissions` and set the `.perms_map` property. Refer to the source code for details.
|
To use custom model permissions, override `DjangoModelPermissions` and set the `.perms_map` property. Refer to the source code for details.
|
||||||
|
|
||||||
|
#### Using with views that do not include a `queryset` attribute.
|
||||||
|
|
||||||
|
If you're using this permission with a view that uses an overridden `get_queryset()` method there may not be a `queryset` attribute on the view. In this case we suggest also marking the view with a sential queryset, so that this class can determine the required permissions. For example:
|
||||||
|
|
||||||
|
queryset = User.objects.none() # Required for DjangoModelPermissions
|
||||||
|
|
||||||
## DjangoModelPermissionsOrAnonReadOnly
|
## DjangoModelPermissionsOrAnonReadOnly
|
||||||
|
|
||||||
Similar to `DjangoModelPermissions`, but also allows unauthenticated users to have read-only access to the API.
|
Similar to `DjangoModelPermissions`, but also allows unauthenticated users to have read-only access to the API.
|
||||||
|
@ -126,7 +138,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].
|
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].
|
||||||
|
|
||||||
When applied to a view that has a `.model` 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. 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.
|
* `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.
|
* `PUT` and `PATCH` requests require the user to have the `change` permission on the model instance.
|
||||||
|
@ -237,7 +249,8 @@ The [REST Condition][rest-condition] package is another extension for building c
|
||||||
[cite]: https://developer.apple.com/library/mac/#documentation/security/Conceptual/AuthenticationAndAuthorizationGuide/Authorization/Authorization.html
|
[cite]: https://developer.apple.com/library/mac/#documentation/security/Conceptual/AuthenticationAndAuthorizationGuide/Authorization/Authorization.html
|
||||||
[authentication]: authentication.md
|
[authentication]: authentication.md
|
||||||
[throttling]: throttling.md
|
[throttling]: throttling.md
|
||||||
[contribauth]: https://docs.djangoproject.com/en/1.0/topics/auth/#permissions
|
[filtering]: filtering.md
|
||||||
|
[contribauth]: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#custom-permissions
|
||||||
[objectpermissions]: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#handling-object-permissions
|
[objectpermissions]: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#handling-object-permissions
|
||||||
[guardian]: https://github.com/lukaszb/django-guardian
|
[guardian]: https://github.com/lukaszb/django-guardian
|
||||||
[get_objects_for_user]: http://pythonhosted.org/django-guardian/api/guardian.shortcuts.html#get-objects-for-user
|
[get_objects_for_user]: http://pythonhosted.org/django-guardian/api/guardian.shortcuts.html#get-objects-for-user
|
||||||
|
|
|
@ -138,6 +138,26 @@ Renders the request data into `YAML`.
|
||||||
|
|
||||||
Requires the `pyyaml` package to be installed.
|
Requires the `pyyaml` package to be installed.
|
||||||
|
|
||||||
|
Note that non-ascii characters will be rendered using `\uXXXX` character escape. For example:
|
||||||
|
|
||||||
|
unicode black star: "\u2605"
|
||||||
|
|
||||||
|
**.media_type**: `application/yaml`
|
||||||
|
|
||||||
|
**.format**: `'.yaml'`
|
||||||
|
|
||||||
|
**.charset**: `utf-8`
|
||||||
|
|
||||||
|
## UnicodeYAMLRenderer
|
||||||
|
|
||||||
|
Renders the request data into `YAML`.
|
||||||
|
|
||||||
|
Requires the `pyyaml` package to be installed.
|
||||||
|
|
||||||
|
Note that non-ascii characters will not be character escaped. For example:
|
||||||
|
|
||||||
|
unicode black star: ★
|
||||||
|
|
||||||
**.media_type**: `application/yaml`
|
**.media_type**: `application/yaml`
|
||||||
|
|
||||||
**.format**: `'.yaml'`
|
**.format**: `'.yaml'`
|
||||||
|
|
|
@ -41,9 +41,9 @@ The example above would generate the following URL patterns:
|
||||||
|
|
||||||
**Note**: The `base_name` argument is used to specify the initial part of the view name pattern. In the example above, that's the `user` or `account` part.
|
**Note**: The `base_name` argument is used to specify the initial part of the view name pattern. In the example above, that's the `user` or `account` part.
|
||||||
|
|
||||||
Typically you won't *need* to specify the `base-name` argument, but if you have a viewset where you've defined a custom `get_queryset` method, then the viewset may not have any `.model` or `.queryset` attribute set. If you try to register that viewset you'll see an error like this:
|
Typically you won't *need* to specify the `base-name` argument, but if you have a viewset where you've defined a custom `get_queryset` method, then the viewset may not have a `.queryset` attribute set. If you try to register that viewset you'll see an error like this:
|
||||||
|
|
||||||
'base_name' argument not specified, and could not automatically determine the name from the viewset, as it does not have a '.model' or '.queryset' attribute.
|
'base_name' argument not specified, and could not automatically determine the name from the viewset, as it does not have a '.queryset' attribute.
|
||||||
|
|
||||||
This means you'll need to explicitly set the `base_name` argument when registering the viewset, as it could not be automatically determined from the model name.
|
This means you'll need to explicitly set the `base_name` argument when registering the viewset, as it could not be automatically determined from the model name.
|
||||||
|
|
||||||
|
@ -51,13 +51,16 @@ This means you'll need to explicitly set the `base_name` argument when registeri
|
||||||
|
|
||||||
### Extra link and actions
|
### Extra link and actions
|
||||||
|
|
||||||
Any methods on the viewset decorated with `@link` or `@action` will also be routed.
|
Any methods on the viewset decorated with `@detail_route` or `@list_route` will also be routed.
|
||||||
For example, given a method like this on the `UserViewSet` class:
|
For example, given a method like this on the `UserViewSet` class:
|
||||||
|
|
||||||
from myapp.permissions import IsAdminOrIsSelf
|
from myapp.permissions import IsAdminOrIsSelf
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import detail_route
|
||||||
|
|
||||||
@action(permission_classes=[IsAdminOrIsSelf])
|
class UserViewSet(ModelViewSet):
|
||||||
|
...
|
||||||
|
|
||||||
|
@detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf])
|
||||||
def set_password(self, request, pk=None):
|
def set_password(self, request, pk=None):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@ -65,22 +68,24 @@ The following URL pattern would additionally be generated:
|
||||||
|
|
||||||
* URL pattern: `^users/{pk}/set_password/$` Name: `'user-set-password'`
|
* URL pattern: `^users/{pk}/set_password/$` Name: `'user-set-password'`
|
||||||
|
|
||||||
|
For more information see the viewset documentation on [marking extra actions for routing][route-decorators].
|
||||||
|
|
||||||
# API Guide
|
# API Guide
|
||||||
|
|
||||||
## SimpleRouter
|
## SimpleRouter
|
||||||
|
|
||||||
This router includes routes for the standard set of `list`, `create`, `retrieve`, `update`, `partial_update` and `destroy` actions. The viewset can also mark additional methods to be routed, using the `@link` or `@action` decorators.
|
This router includes routes for the standard set of `list`, `create`, `retrieve`, `update`, `partial_update` and `destroy` actions. The viewset can also mark additional methods to be routed, using the `@detail_route` or `@list_route` decorators.
|
||||||
|
|
||||||
<table border=1>
|
<table border=1>
|
||||||
<tr><th>URL Style</th><th>HTTP Method</th><th>Action</th><th>URL Name</th></tr>
|
<tr><th>URL Style</th><th>HTTP Method</th><th>Action</th><th>URL Name</th></tr>
|
||||||
<tr><td rowspan=2>{prefix}/</td><td>GET</td><td>list</td><td rowspan=2>{basename}-list</td></tr></tr>
|
<tr><td rowspan=2>{prefix}/</td><td>GET</td><td>list</td><td rowspan=2>{basename}-list</td></tr></tr>
|
||||||
<tr><td>POST</td><td>create</td></tr>
|
<tr><td>POST</td><td>create</td></tr>
|
||||||
|
<tr><td>{prefix}/{methodname}/</td><td>GET, or as specified by `methods` argument</td><td>`@list_route` decorated method</td><td>{basename}-{methodname}</td></tr>
|
||||||
<tr><td rowspan=4>{prefix}/{lookup}/</td><td>GET</td><td>retrieve</td><td rowspan=4>{basename}-detail</td></tr></tr>
|
<tr><td rowspan=4>{prefix}/{lookup}/</td><td>GET</td><td>retrieve</td><td rowspan=4>{basename}-detail</td></tr></tr>
|
||||||
<tr><td>PUT</td><td>update</td></tr>
|
<tr><td>PUT</td><td>update</td></tr>
|
||||||
<tr><td>PATCH</td><td>partial_update</td></tr>
|
<tr><td>PATCH</td><td>partial_update</td></tr>
|
||||||
<tr><td>DELETE</td><td>destroy</td></tr>
|
<tr><td>DELETE</td><td>destroy</td></tr>
|
||||||
<tr><td rowspan=2>{prefix}/{lookup}/{methodname}/</td><td>GET</td><td>@link decorated method</td><td rowspan=2>{basename}-{methodname}</td></tr>
|
<tr><td>{prefix}/{lookup}/{methodname}/</td><td>GET, or as specified by `methods` argument</td><td>`@detail_route` decorated method</td><td>{basename}-{methodname}</td></tr>
|
||||||
<tr><td>POST</td><td>@action decorated method</td></tr>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
By default the URLs created by `SimpleRouter` are appended with a trailing slash.
|
By default the URLs created by `SimpleRouter` are appended with a trailing slash.
|
||||||
|
@ -90,6 +95,12 @@ This behavior can be modified by setting the `trailing_slash` argument to `False
|
||||||
|
|
||||||
Trailing slashes are conventional in Django, but are not used by default in some other frameworks such as Rails. Which style you choose to use is largely a matter of preference, although some javascript frameworks may expect a particular routing style.
|
Trailing slashes are conventional in Django, but are not used by default in some other frameworks such as Rails. Which style you choose to use is largely a matter of preference, although some javascript frameworks may expect a particular routing style.
|
||||||
|
|
||||||
|
The router will match lookup values containing any characters except slashes and period characters. For a more restrictive (or lenient) lookup pattern, set the `lookup_value_regex` attribute on the viewset. For example, you can limit the lookup to valid UUIDs:
|
||||||
|
|
||||||
|
class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
|
||||||
|
lookup_field = 'my_model_id'
|
||||||
|
lookup_value_regex = '[0-9a-f]{32}'
|
||||||
|
|
||||||
## DefaultRouter
|
## DefaultRouter
|
||||||
|
|
||||||
This router is similar to `SimpleRouter` as above, but additionally includes a default API root view, that returns a response containing hyperlinks to all the list views. It also generates routes for optional `.json` style format suffixes.
|
This router is similar to `SimpleRouter` as above, but additionally includes a default API root view, that returns a response containing hyperlinks to all the list views. It also generates routes for optional `.json` style format suffixes.
|
||||||
|
@ -99,12 +110,12 @@ This router is similar to `SimpleRouter` as above, but additionally includes a d
|
||||||
<tr><td>[.format]</td><td>GET</td><td>automatically generated root view</td><td>api-root</td></tr></tr>
|
<tr><td>[.format]</td><td>GET</td><td>automatically generated root view</td><td>api-root</td></tr></tr>
|
||||||
<tr><td rowspan=2>{prefix}/[.format]</td><td>GET</td><td>list</td><td rowspan=2>{basename}-list</td></tr></tr>
|
<tr><td rowspan=2>{prefix}/[.format]</td><td>GET</td><td>list</td><td rowspan=2>{basename}-list</td></tr></tr>
|
||||||
<tr><td>POST</td><td>create</td></tr>
|
<tr><td>POST</td><td>create</td></tr>
|
||||||
|
<tr><td>{prefix}/{methodname}/[.format]</td><td>GET, or as specified by `methods` argument</td><td>`@list_route` decorated method</td><td>{basename}-{methodname}</td></tr>
|
||||||
<tr><td rowspan=4>{prefix}/{lookup}/[.format]</td><td>GET</td><td>retrieve</td><td rowspan=4>{basename}-detail</td></tr></tr>
|
<tr><td rowspan=4>{prefix}/{lookup}/[.format]</td><td>GET</td><td>retrieve</td><td rowspan=4>{basename}-detail</td></tr></tr>
|
||||||
<tr><td>PUT</td><td>update</td></tr>
|
<tr><td>PUT</td><td>update</td></tr>
|
||||||
<tr><td>PATCH</td><td>partial_update</td></tr>
|
<tr><td>PATCH</td><td>partial_update</td></tr>
|
||||||
<tr><td>DELETE</td><td>destroy</td></tr>
|
<tr><td>DELETE</td><td>destroy</td></tr>
|
||||||
<tr><td rowspan=2>{prefix}/{lookup}/{methodname}/[.format]</td><td>GET</td><td>@link decorated method</td><td rowspan=2>{basename}-{methodname}</td></tr>
|
<tr><td>{prefix}/{lookup}/{methodname}/[.format]</td><td>GET, or as specified by `methods` argument</td><td>`@detail_route` decorated method</td><td>{basename}-{methodname}</td></tr>
|
||||||
<tr><td>POST</td><td>@action decorated method</td></tr>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
As with `SimpleRouter` the trailing slashes on the URL routes can be removed by setting the `trailing_slash` argument to `False` when instantiating the router.
|
As with `SimpleRouter` the trailing slashes on the URL routes can be removed by setting the `trailing_slash` argument to `False` when instantiating the router.
|
||||||
|
@ -133,28 +144,87 @@ The arguments to the `Route` named tuple are:
|
||||||
|
|
||||||
**initkwargs**: A dictionary of any additional arguments that should be passed when instantiating the view. Note that the `suffix` argument is reserved for identifying the viewset type, used when generating the view name and breadcrumb links.
|
**initkwargs**: A dictionary of any additional arguments that should be passed when instantiating the view. Note that the `suffix` argument is reserved for identifying the viewset type, used when generating the view name and breadcrumb links.
|
||||||
|
|
||||||
|
## Customizing dynamic routes
|
||||||
|
|
||||||
|
You can also customize how the `@list_route` and `@detail_route` decorators are routed.
|
||||||
|
To route either or both of these decorators, include a `DynamicListRoute` and/or `DynamicDetailRoute` named tuple in the `.routes` list.
|
||||||
|
|
||||||
|
The arguments to `DynamicListRoute` and `DynamicDetailRoute` are:
|
||||||
|
|
||||||
|
**url**: A string representing the URL to be routed. May include the same format strings as `Route`, and additionally accepts the `{methodname}` and `{methodnamehyphen}` format strings.
|
||||||
|
|
||||||
|
**name**: The name of the URL as used in `reverse` calls. May include the following format strings: `{basename}`, `{methodname}` and `{methodnamehyphen}`.
|
||||||
|
|
||||||
|
**initkwargs**: A dictionary of any additional arguments that should be passed when instantiating the view.
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
The following example will only route to the `list` and `retrieve` actions, and does not use the trailing slash convention.
|
The following example will only route to the `list` and `retrieve` actions, and does not use the trailing slash convention.
|
||||||
|
|
||||||
from rest_framework.routers import Route, SimpleRouter
|
from rest_framework.routers import Route, DynamicDetailRoute, SimpleRouter
|
||||||
|
|
||||||
class ReadOnlyRouter(SimpleRouter):
|
class CustomReadOnlyRouter(SimpleRouter):
|
||||||
"""
|
"""
|
||||||
A router for read-only APIs, which doesn't use trailing slashes.
|
A router for read-only APIs, which doesn't use trailing slashes.
|
||||||
"""
|
"""
|
||||||
routes = [
|
routes = [
|
||||||
Route(url=r'^{prefix}$',
|
Route(
|
||||||
|
url=r'^{prefix}$',
|
||||||
mapping={'get': 'list'},
|
mapping={'get': 'list'},
|
||||||
name='{basename}-list',
|
name='{basename}-list',
|
||||||
initkwargs={'suffix': 'List'}),
|
initkwargs={'suffix': 'List'}
|
||||||
Route(url=r'^{prefix}/{lookup}$',
|
),
|
||||||
|
Route(
|
||||||
|
url=r'^{prefix}/{lookup}$',
|
||||||
mapping={'get': 'retrieve'},
|
mapping={'get': 'retrieve'},
|
||||||
name='{basename}-detail',
|
name='{basename}-detail',
|
||||||
initkwargs={'suffix': 'Detail'})
|
initkwargs={'suffix': 'Detail'}
|
||||||
|
),
|
||||||
|
DynamicDetailRoute(
|
||||||
|
url=r'^{prefix}/{lookup}/{methodnamehyphen}$',
|
||||||
|
name='{basename}-{methodnamehyphen}',
|
||||||
|
initkwargs={}
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
The `SimpleRouter` class provides another example of setting the `.routes` attribute.
|
Let's take a look at the routes our `CustomReadOnlyRouter` would generate for a simple viewset.
|
||||||
|
|
||||||
|
`views.py`:
|
||||||
|
|
||||||
|
class UserViewSet(viewsets.ReadOnlyModelViewSet):
|
||||||
|
"""
|
||||||
|
A viewset that provides the standard actions
|
||||||
|
"""
|
||||||
|
queryset = User.objects.all()
|
||||||
|
serializer_class = UserSerializer
|
||||||
|
lookup_field = 'username'
|
||||||
|
|
||||||
|
@detail_route()
|
||||||
|
def group_names(self, request):
|
||||||
|
"""
|
||||||
|
Returns a list of all the group names that the given
|
||||||
|
user belongs to.
|
||||||
|
"""
|
||||||
|
user = self.get_object()
|
||||||
|
groups = user.groups.all()
|
||||||
|
return Response([group.name for group in groups])
|
||||||
|
|
||||||
|
`urls.py`:
|
||||||
|
|
||||||
|
router = CustomReadOnlyRouter()
|
||||||
|
router.register('users', UserViewSet)
|
||||||
|
urlpatterns = router.urls
|
||||||
|
|
||||||
|
The following mappings would be generated...
|
||||||
|
|
||||||
|
<table border=1>
|
||||||
|
<tr><th>URL</th><th>HTTP Method</th><th>Action</th><th>URL Name</th></tr>
|
||||||
|
<tr><td>/users</td><td>GET</td><td>list</td><td>user-list</td></tr>
|
||||||
|
<tr><td>/users/{username}</td><td>GET</td><td>retrieve</td><td>user-detail</td></tr>
|
||||||
|
<tr><td>/users/{username}/group-names</td><td>GET</td><td>group_names</td><td>user-group-names</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
For another example of setting the `.routes` attribute, see the source code for the `SimpleRouter` class.
|
||||||
|
|
||||||
## Advanced custom routers
|
## Advanced custom routers
|
||||||
|
|
||||||
|
@ -179,7 +249,17 @@ The [wq.db package][wq.db] provides an advanced [Router][wq.db-router] class (an
|
||||||
|
|
||||||
app.router.register_model(MyModel)
|
app.router.register_model(MyModel)
|
||||||
|
|
||||||
|
## DRF-extensions
|
||||||
|
|
||||||
|
The [`DRF-extensions` package][drf-extensions] provides [routers][drf-extensions-routers] for creating [nested viewsets][drf-extensions-nested-viewsets], [collection level controllers][drf-extensions-collection-level-controllers] with [customizable endpoint names][drf-extensions-customizable-endpoint-names].
|
||||||
|
|
||||||
[cite]: http://guides.rubyonrails.org/routing.html
|
[cite]: http://guides.rubyonrails.org/routing.html
|
||||||
|
[route-decorators]: viewsets.html#marking-extra-actions-for-routing
|
||||||
[drf-nested-routers]: https://github.com/alanjds/drf-nested-routers
|
[drf-nested-routers]: https://github.com/alanjds/drf-nested-routers
|
||||||
[wq.db]: http://wq.io/wq.db
|
[wq.db]: http://wq.io/wq.db
|
||||||
[wq.db-router]: http://wq.io/docs/app.py
|
[wq.db-router]: http://wq.io/docs/app.py
|
||||||
|
[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
|
||||||
|
[drf-extensions-collection-level-controllers]: http://chibisov.github.io/drf-extensions/docs/#collection-level-controllers
|
||||||
|
[drf-extensions-customizable-endpoint-names]: http://chibisov.github.io/drf-extensions/docs/#controller-endpoint-name
|
||||||
|
|
|
@ -73,8 +73,8 @@ Sometimes when serializing objects, you may not want to represent everything exa
|
||||||
|
|
||||||
If you need to customize the serialized value of a particular field, you can do this by creating a `transform_<fieldname>` method. For example if you needed to render some markdown from a text field:
|
If you need to customize the serialized value of a particular field, you can do this by creating a `transform_<fieldname>` method. For example if you needed to render some markdown from a text field:
|
||||||
|
|
||||||
description = serializers.TextField()
|
description = serializers.CharField()
|
||||||
description_html = serializers.TextField(source='description', read_only=True)
|
description_html = serializers.CharField(source='description', read_only=True)
|
||||||
|
|
||||||
def transform_description_html(self, obj, value):
|
def transform_description_html(self, obj, value):
|
||||||
from django.contrib.markup.templatetags.markup import markdown
|
from django.contrib.markup.templatetags.markup import markdown
|
||||||
|
@ -464,7 +464,7 @@ For more specific requirements such as specifying a different lookup for each fi
|
||||||
model = Account
|
model = Account
|
||||||
fields = ('url', 'account_name', 'users', 'created')
|
fields = ('url', 'account_name', 'users', 'created')
|
||||||
|
|
||||||
## Overiding the URL field behavior
|
## Overriding the URL field behavior
|
||||||
|
|
||||||
The name of the URL field defaults to 'url'. You can override this globally, by using the `URL_FIELD_NAME` setting.
|
The name of the URL field defaults to 'url'. You can override this globally, by using the `URL_FIELD_NAME` setting.
|
||||||
|
|
||||||
|
@ -478,7 +478,7 @@ You can also override this on a per-serializer basis by using the `url_field_nam
|
||||||
|
|
||||||
**Note**: The generic view implementations normally generate a `Location` header in response to successful `POST` requests. Serializers using `url_field_name` option will not have this header automatically included by the view. If you need to do so you will ned to also override the view's `get_success_headers()` method.
|
**Note**: The generic view implementations normally generate a `Location` header in response to successful `POST` requests. Serializers using `url_field_name` option will not have this header automatically included by the view. If you need to do so you will ned to also override the view's `get_success_headers()` method.
|
||||||
|
|
||||||
You can also overide the URL field's view name and lookup field without overriding the field explicitly, by using the `view_name` and `lookup_field` options, like so:
|
You can also override the URL field's view name and lookup field without overriding the field explicitly, by using the `view_name` and `lookup_field` options, like so:
|
||||||
|
|
||||||
class AccountSerializer(serializers.HyperlinkedModelSerializer):
|
class AccountSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -580,7 +580,27 @@ The following custom model serializer could be used as a base class for model se
|
||||||
def get_pk_field(self, model_field):
|
def get_pk_field(self, model_field):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Third party packages
|
||||||
|
|
||||||
|
The following third party packages are also available.
|
||||||
|
|
||||||
|
## MongoengineModelSerializer
|
||||||
|
|
||||||
|
The [django-rest-framework-mongoengine][mongoengine] package provides a `MongoEngineModelSerializer` serializer class that supports using MongoDB as the storage layer for Django REST framework.
|
||||||
|
|
||||||
|
## GeoFeatureModelSerializer
|
||||||
|
|
||||||
|
The [django-rest-framework-gis][django-rest-framework-gis] package provides a `GeoFeatureModelSerializer` serializer class that supports GeoJSON both for read and write operations.
|
||||||
|
|
||||||
|
## HStoreSerializer
|
||||||
|
|
||||||
|
The [django-rest-framework-hstore][django-rest-framework-hstore] package provides an `HStoreSerializer` to support [django-hstore][django-hstore] `DictionaryField` model field and its `schema-mode` feature.
|
||||||
|
|
||||||
[cite]: https://groups.google.com/d/topic/django-users/sVFaOfQi4wY/discussion
|
[cite]: https://groups.google.com/d/topic/django-users/sVFaOfQi4wY/discussion
|
||||||
[relations]: relations.md
|
[relations]: relations.md
|
||||||
|
[mongoengine]: https://github.com/umutbozkurt/django-rest-framework-mongoengine
|
||||||
|
[django-rest-framework-gis]: https://github.com/djangonauts/django-rest-framework-gis
|
||||||
|
[django-rest-framework-hstore]: https://github.com/djangonauts/django-rest-framework-hstore
|
||||||
|
[django-hstore]: https://github.com/djangonauts/django-hstore
|
||||||
|
|
|
@ -100,12 +100,6 @@ Default: `'rest_framework.negotiation.DefaultContentNegotiation'`
|
||||||
|
|
||||||
*The following settings control the behavior of the generic class based views.*
|
*The following settings control the behavior of the generic class based views.*
|
||||||
|
|
||||||
#### DEFAULT_MODEL_SERIALIZER_CLASS
|
|
||||||
|
|
||||||
A class that determines the default type of model serializer that should be used by a generic view if `model` is specified, but `serializer_class` is not provided.
|
|
||||||
|
|
||||||
Default: `'rest_framework.serializers.ModelSerializer'`
|
|
||||||
|
|
||||||
#### DEFAULT_PAGINATION_SERIALIZER_CLASS
|
#### DEFAULT_PAGINATION_SERIALIZER_CLASS
|
||||||
|
|
||||||
A class the determines the default serialization style for paginated responses.
|
A class the determines the default serialization style for paginated responses.
|
||||||
|
@ -377,5 +371,11 @@ The name of a parameter in the URL conf that may be used to provide a format suf
|
||||||
|
|
||||||
Default: `'format'`
|
Default: `'format'`
|
||||||
|
|
||||||
|
#### NUM_PROXIES
|
||||||
|
|
||||||
|
An integer of 0 or more, that may be used to specify the number of application proxies that the API runs behind. This allows throttling to more accurately identify client IP addresses. If set to `None` then less strict IP matching will be used by the throttle classes.
|
||||||
|
|
||||||
|
Default: `None`
|
||||||
|
|
||||||
[cite]: http://www.python.org/dev/peps/pep-0020/
|
[cite]: http://www.python.org/dev/peps/pep-0020/
|
||||||
[strftime]: http://docs.python.org/2/library/time.html#time.strftime
|
[strftime]: http://docs.python.org/2/library/time.html#time.strftime
|
||||||
|
|
|
@ -58,7 +58,7 @@ using the `APIView` class based views.
|
||||||
|
|
||||||
Or, if you're using the `@api_view` decorator with function based views.
|
Or, if you're using the `@api_view` decorator with function based views.
|
||||||
|
|
||||||
@api_view('GET')
|
@api_view(['GET'])
|
||||||
@throttle_classes([UserRateThrottle])
|
@throttle_classes([UserRateThrottle])
|
||||||
def example_view(request, format=None):
|
def example_view(request, format=None):
|
||||||
content = {
|
content = {
|
||||||
|
@ -66,6 +66,16 @@ Or, if you're using the `@api_view` decorator with function based views.
|
||||||
}
|
}
|
||||||
return Response(content)
|
return Response(content)
|
||||||
|
|
||||||
|
## How clients are identified
|
||||||
|
|
||||||
|
The `X-Forwarded-For` and `Remote-Addr` HTTP headers are used to uniquely identify client IP addresses for throttling. If the `X-Forwarded-For` header is present then it will be used, otherwise the value of the `Remote-Addr` header will be used.
|
||||||
|
|
||||||
|
If you need to strictly identify unique client IP addresses, you'll need to first configure the number of application proxies that the API runs behind by setting the `NUM_PROXIES` setting. This setting should be an integer of zero or more. If set to non-zero then the client IP will be identified as being the last IP address in the `X-Forwarded-For` header, once any application proxy IP addresses have first been excluded. If set to zero, then the `Remote-Addr` header will always be used as the identifying IP address.
|
||||||
|
|
||||||
|
It is important to understand that if you configure the `NUM_PROXIES` setting, then all clients behind a unique [NAT'd](http://en.wikipedia.org/wiki/Network_address_translation) gateway will be treated as a single client.
|
||||||
|
|
||||||
|
Further context on how the `X-Forwarded-For` header works, and identifing a remote client IP can be [found here][identifing-clients].
|
||||||
|
|
||||||
## Setting up the cache
|
## Setting up the cache
|
||||||
|
|
||||||
The throttle classes provided by REST framework use Django's cache backend. You should make sure that you've set appropriate [cache settings][cache-setting]. The default value of `LocMemCache` backend should be okay for simple setups. See Django's [cache documentation][cache-docs] for more details.
|
The throttle classes provided by REST framework use Django's cache backend. You should make sure that you've set appropriate [cache settings][cache-setting]. The default value of `LocMemCache` backend should be okay for simple setups. See Django's [cache documentation][cache-docs] for more details.
|
||||||
|
@ -178,5 +188,6 @@ The following is an example of a rate throttle, that will randomly throttle 1 in
|
||||||
|
|
||||||
[cite]: https://dev.twitter.com/docs/error-codes-responses
|
[cite]: https://dev.twitter.com/docs/error-codes-responses
|
||||||
[permissions]: permissions.md
|
[permissions]: permissions.md
|
||||||
|
[identifing-clients]: http://oxpedia.org/wiki/index.php?title=AppSuite:Grizzly#Multiple_Proxies_in_front_of_the_cluster
|
||||||
[cache-setting]: https://docs.djangoproject.com/en/dev/ref/settings/#caches
|
[cache-setting]: https://docs.djangoproject.com/en/dev/ref/settings/#caches
|
||||||
[cache-docs]: https://docs.djangoproject.com/en/dev/topics/cache/#setting-up-the-cache
|
[cache-docs]: https://docs.djangoproject.com/en/dev/topics/cache/#setting-up-the-cache
|
||||||
|
|
|
@ -70,7 +70,7 @@ There are two main advantages of using a `ViewSet` class over using a `View` cla
|
||||||
|
|
||||||
Both of these come with a trade-off. Using regular views and URL confs is more explicit and gives you more control. ViewSets are helpful if you want to get up and running quickly, or when you have a large API and you want to enforce a consistent URL configuration throughout.
|
Both of these come with a trade-off. Using regular views and URL confs is more explicit and gives you more control. ViewSets are helpful if you want to get up and running quickly, or when you have a large API and you want to enforce a consistent URL configuration throughout.
|
||||||
|
|
||||||
## Marking extra methods for routing
|
## Marking extra actions for routing
|
||||||
|
|
||||||
The default routers included with REST framework will provide routes for a standard set of create/retrieve/update/destroy style operations, as shown below:
|
The default routers included with REST framework will provide routes for a standard set of create/retrieve/update/destroy style operations, as shown below:
|
||||||
|
|
||||||
|
@ -101,14 +101,16 @@ The default routers included with REST framework will provide routes for a stand
|
||||||
def destroy(self, request, pk=None):
|
def destroy(self, request, pk=None):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
If you have ad-hoc methods that you need to be routed to, you can mark them as requiring routing using the `@link` or `@action` decorators. The `@link` decorator will route `GET` requests, and the `@action` decorator will route `POST` requests.
|
If you have ad-hoc methods that you need to be routed to, you can mark them as requiring routing using the `@detail_route` or `@list_route` decorators.
|
||||||
|
|
||||||
|
The `@detail_route` decorator contains `pk` in its URL pattern and is intended for methods which require a single instance. The `@list_route` decorator is intended for methods which operate on a list of objects.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from rest_framework import viewsets
|
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.decorators import action
|
from rest_framework import viewsets
|
||||||
|
from rest_framework.decorators import detail_route, list_route
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from myapp.serializers import UserSerializer, PasswordSerializer
|
from myapp.serializers import UserSerializer, PasswordSerializer
|
||||||
|
|
||||||
|
@ -119,7 +121,7 @@ For example:
|
||||||
queryset = User.objects.all()
|
queryset = User.objects.all()
|
||||||
serializer_class = UserSerializer
|
serializer_class = UserSerializer
|
||||||
|
|
||||||
@action()
|
@detail_route(methods=['post'])
|
||||||
def set_password(self, request, pk=None):
|
def set_password(self, request, pk=None):
|
||||||
user = self.get_object()
|
user = self.get_object()
|
||||||
serializer = PasswordSerializer(data=request.DATA)
|
serializer = PasswordSerializer(data=request.DATA)
|
||||||
|
@ -131,21 +133,27 @@ For example:
|
||||||
return Response(serializer.errors,
|
return Response(serializer.errors,
|
||||||
status=status.HTTP_400_BAD_REQUEST)
|
status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
The `@action` and `@link` decorators can additionally take extra arguments that will be set for the routed view only. 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)
|
||||||
|
return Response(serializer.data)
|
||||||
|
|
||||||
@action(permission_classes=[IsAdminOrIsSelf])
|
The decorators can additionally take extra arguments that will be set for the routed view only. For example...
|
||||||
|
|
||||||
|
@detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf])
|
||||||
def set_password(self, request, pk=None):
|
def set_password(self, request, pk=None):
|
||||||
...
|
...
|
||||||
|
|
||||||
The `@action` decorator will route `POST` requests by default, but may also accept other HTTP methods, by using the `method` argument. For example:
|
Theses decorators will route `GET` requests by default, but may also accept other HTTP methods, by using the `methods` argument. For example:
|
||||||
|
|
||||||
@action(methods=['POST', 'DELETE'])
|
@detail_route(methods=['post', 'delete'])
|
||||||
def unset_password(self, request, pk=None):
|
def unset_password(self, request, pk=None):
|
||||||
...
|
...
|
||||||
|
|
||||||
The two new actions will then be available at the urls `^users/{pk}/set_password/$` and `^users/{pk}/unset_password/$`
|
The two new actions will then be available at the urls `^users/{pk}/set_password/$` and `^users/{pk}/unset_password/$`
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# API Reference
|
# API Reference
|
||||||
|
|
|
@ -307,3 +307,76 @@ table {
|
||||||
.side-nav {
|
.side-nav {
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ul.sponsor.diamond li a {
|
||||||
|
float: left;
|
||||||
|
width: 600px;
|
||||||
|
height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
margin: 10px 70px;
|
||||||
|
padding: 300px 0 0 0;
|
||||||
|
background-position: 0 50%;
|
||||||
|
background-size: 600px auto;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
font-size: 200%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1000px) {
|
||||||
|
ul.sponsor.diamond li a {
|
||||||
|
float: left;
|
||||||
|
width: 300px;
|
||||||
|
height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
margin: 10px 40px;
|
||||||
|
padding: 300px 0 0 0;
|
||||||
|
background-position: 0 50%;
|
||||||
|
background-size: 280px auto;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
font-size: 150%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.sponsor.platinum li a {
|
||||||
|
float: left;
|
||||||
|
width: 300px;
|
||||||
|
height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
margin: 10px 40px;
|
||||||
|
padding: 300px 0 0 0;
|
||||||
|
background-position: 0 50%;
|
||||||
|
background-size: 280px auto;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
font-size: 150%;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.sponsor.gold li a {
|
||||||
|
float: left;
|
||||||
|
width: 130px;
|
||||||
|
height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
margin: 10px 30px;
|
||||||
|
padding: 150px 0 0 0;
|
||||||
|
background-position: 0 50%;
|
||||||
|
background-size: 130px auto;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
font-size: 120%;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.sponsor.silver li a {
|
||||||
|
float: left;
|
||||||
|
width: 130px;
|
||||||
|
height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
margin: 10px 30px;
|
||||||
|
padding: 150px 0 0 0;
|
||||||
|
background-position: 0 50%;
|
||||||
|
background-size: 130px auto;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
font-size: 120%;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.sponsor {
|
||||||
|
list-style: none;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
BIN
docs/img/1-kuwaitnet.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
docs/img/labels-and-milestones.png
Normal file
After Width: | Height: | Size: 82 KiB |
BIN
docs/img/sponsors/0-eventbrite.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
docs/img/sponsors/1-cyan.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
docs/img/sponsors/1-divio.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
docs/img/sponsors/1-kuwaitnet.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
docs/img/sponsors/1-lulu.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
docs/img/sponsors/1-potato.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
docs/img/sponsors/1-purplebit.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
docs/img/sponsors/1-runscope.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
docs/img/sponsors/1-simple-energy.png
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
docs/img/sponsors/1-vokal_interactive.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
docs/img/sponsors/1-wiredrive.png
Normal file
After Width: | Height: | Size: 7.9 KiB |
BIN
docs/img/sponsors/2-byte.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
docs/img/sponsors/2-compile.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
docs/img/sponsors/2-crate.png
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
docs/img/sponsors/2-cryptico.png
Normal file
After Width: | Height: | Size: 9.7 KiB |
BIN
docs/img/sponsors/2-django.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
docs/img/sponsors/2-galileo_press.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
docs/img/sponsors/2-heroku.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
docs/img/sponsors/2-hipflask.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
docs/img/sponsors/2-hipo.png
Normal file
After Width: | Height: | Size: 7.9 KiB |
BIN
docs/img/sponsors/2-koordinates.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
docs/img/sponsors/2-laterpay.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
docs/img/sponsors/2-lightning_kite.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
docs/img/sponsors/2-mirus_research.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
docs/img/sponsors/2-nexthub.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
docs/img/sponsors/2-opbeat.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
docs/img/sponsors/2-prorenata.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
docs/img/sponsors/2-pulsecode.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
docs/img/sponsors/2-rapasso.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
docs/img/sponsors/2-schuberg_philis.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
docs/img/sponsors/2-security_compass.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
docs/img/sponsors/2-sga.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
docs/img/sponsors/2-singing-horse.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
docs/img/sponsors/2-sirono.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
docs/img/sponsors/2-vinta.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
docs/img/sponsors/2-wusawork.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
docs/img/sponsors/3-aba.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
docs/img/sponsors/3-aditium.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
docs/img/sponsors/3-alwaysdata.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
docs/img/sponsors/3-ax_semantics.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
docs/img/sponsors/3-beefarm.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
docs/img/sponsors/3-blimp.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
docs/img/sponsors/3-brightloop.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
docs/img/sponsors/3-cantemo.gif
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
docs/img/sponsors/3-crosswordtracker.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
docs/img/sponsors/3-fluxility.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
docs/img/sponsors/3-garfo.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
docs/img/sponsors/3-gizmag.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
docs/img/sponsors/3-holvi.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
docs/img/sponsors/3-imt_computer_services.png
Normal file
After Width: | Height: | Size: 69 KiB |
BIN
docs/img/sponsors/3-infinite_code.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
docs/img/sponsors/3-ipushpull.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
docs/img/sponsors/3-isl.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
docs/img/sponsors/3-life_the_game.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
docs/img/sponsors/3-makespace.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
docs/img/sponsors/3-nephila.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
docs/img/sponsors/3-openeye.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
docs/img/sponsors/3-pathwright.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
docs/img/sponsors/3-phurba.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
docs/img/sponsors/3-pkgfarm.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
docs/img/sponsors/3-providenz.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
docs/img/sponsors/3-safari.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
docs/img/sponsors/3-shippo.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
docs/img/sponsors/3-teonite.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
BIN
docs/img/sponsors/3-thermondo-gmbh.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
docs/img/sponsors/3-tivix.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
docs/img/sponsors/3-trackmaven.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
docs/img/sponsors/3-transcode.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
docs/img/sponsors/3-triggered_messaging.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
docs/img/sponsors/3-vzzual.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
docs/img/sponsors/3-wildfish.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
|
@ -50,7 +50,7 @@ Some reasons you might want to use REST framework:
|
||||||
REST framework requires the following:
|
REST framework requires the following:
|
||||||
|
|
||||||
* Python (2.6.5+, 2.7, 3.2, 3.3)
|
* Python (2.6.5+, 2.7, 3.2, 3.3)
|
||||||
* Django (1.3, 1.4, 1.5, 1.6)
|
* Django (1.4.2+, 1.5, 1.6, 1.7)
|
||||||
|
|
||||||
The following packages are optional:
|
The following packages are optional:
|
||||||
|
|
||||||
|
@ -96,16 +96,11 @@ Note that the URL path can be whatever you want, but you must include `'rest_fra
|
||||||
|
|
||||||
Let's take a look at a quick example of using REST framework to build a simple model-backed API.
|
Let's take a look at a quick example of using REST framework to build a simple model-backed API.
|
||||||
|
|
||||||
We'll create a read-write API for accessing users and groups.
|
We'll create a read-write API for accessing information on the users of our project.
|
||||||
|
|
||||||
Any global settings for a REST framework API are kept in a single configuration dictionary named `REST_FRAMEWORK`. Start off by adding the following to your `settings.py` module:
|
Any global settings for a REST framework API are kept in a single configuration dictionary named `REST_FRAMEWORK`. Start off by adding the following to your `settings.py` module:
|
||||||
|
|
||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
# Use hyperlinked styles by default.
|
|
||||||
# Only used if the `serializer_class` attribute is not set on a view.
|
|
||||||
'DEFAULT_MODEL_SERIALIZER_CLASS':
|
|
||||||
'rest_framework.serializers.HyperlinkedModelSerializer',
|
|
||||||
|
|
||||||
# Use Django's standard `django.contrib.auth` permissions,
|
# Use Django's standard `django.contrib.auth` permissions,
|
||||||
# or allow read-only access for unauthenticated users.
|
# or allow read-only access for unauthenticated users.
|
||||||
'DEFAULT_PERMISSION_CLASSES': [
|
'DEFAULT_PERMISSION_CLASSES': [
|
||||||
|
@ -118,30 +113,33 @@ Don't forget to make sure you've also added `rest_framework` to your `INSTALLED_
|
||||||
We're ready to create our API now.
|
We're ready to create our API now.
|
||||||
Here's our project's root `urls.py` module:
|
Here's our project's root `urls.py` module:
|
||||||
|
|
||||||
from django.conf.urls import url, patterns, include
|
from django.conf.urls import url, include
|
||||||
from django.contrib.auth.models import User, Group
|
from django.contrib.auth.models import User
|
||||||
from rest_framework import viewsets, routers
|
from rest_framework import routers, serializers, viewsets
|
||||||
|
|
||||||
|
# Serializers define the API representation.
|
||||||
|
class UserSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = ('url', 'username', 'email', 'is_staff')
|
||||||
|
|
||||||
# ViewSets define the view behavior.
|
# ViewSets define the view behavior.
|
||||||
class UserViewSet(viewsets.ModelViewSet):
|
class UserViewSet(viewsets.ModelViewSet):
|
||||||
model = User
|
queryset = User.objects.all()
|
||||||
|
serializer_class = UserSerializer
|
||||||
class GroupViewSet(viewsets.ModelViewSet):
|
|
||||||
model = Group
|
|
||||||
|
|
||||||
|
|
||||||
# Routers provide an easy way of automatically determining the URL conf.
|
# Routers provide an easy way of automatically determining the URL conf.
|
||||||
router = routers.DefaultRouter()
|
router = routers.DefaultRouter()
|
||||||
router.register(r'users', UserViewSet)
|
router.register(r'users', UserViewSet)
|
||||||
router.register(r'groups', GroupViewSet)
|
|
||||||
|
|
||||||
|
|
||||||
# Wire up our API using automatic URL routing.
|
# Wire up our API using automatic URL routing.
|
||||||
# Additionally, we include login URLs for the browseable API.
|
# Additionally, we include login URLs for the browseable API.
|
||||||
urlpatterns = patterns('',
|
urlpatterns = [
|
||||||
url(r'^', include(router.urls)),
|
url(r'^', include(router.urls)),
|
||||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
||||||
)
|
]
|
||||||
|
|
||||||
|
You can now open the API in your browser at [http://127.0.0.1:8000/](http://127.0.0.1:8000/), and view your new 'users' API. If you use the login control in the top right corner you'll also be able to add, create and delete users from the system.
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
|
@ -201,24 +199,16 @@ General guides to using REST framework.
|
||||||
* [2.0 Announcement][rest-framework-2-announcement]
|
* [2.0 Announcement][rest-framework-2-announcement]
|
||||||
* [2.2 Announcement][2.2-announcement]
|
* [2.2 Announcement][2.2-announcement]
|
||||||
* [2.3 Announcement][2.3-announcement]
|
* [2.3 Announcement][2.3-announcement]
|
||||||
|
* [2.4 Announcement][2.4-announcement]
|
||||||
|
* [Kickstarter Announcement][kickstarter-announcement]
|
||||||
* [Release Notes][release-notes]
|
* [Release Notes][release-notes]
|
||||||
* [Credits][credits]
|
* [Credits][credits]
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
If you want to work on REST framework itself, clone the repository, then...
|
See the [Contribution guidelines][contributing] for information on how to clone
|
||||||
|
the repository, run the test suite and contribute changes back to REST
|
||||||
Build the docs:
|
Framework.
|
||||||
|
|
||||||
./mkdocs.py
|
|
||||||
|
|
||||||
Run the tests:
|
|
||||||
|
|
||||||
./rest_framework/runtests/runtests.py
|
|
||||||
|
|
||||||
To run the tests against all supported configurations, first install [the tox testing tool][tox] globally, using `pip install tox`, then simply run `tox`:
|
|
||||||
|
|
||||||
tox
|
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
|
@ -325,6 +315,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
[rest-framework-2-announcement]: topics/rest-framework-2-announcement.md
|
[rest-framework-2-announcement]: topics/rest-framework-2-announcement.md
|
||||||
[2.2-announcement]: topics/2.2-announcement.md
|
[2.2-announcement]: topics/2.2-announcement.md
|
||||||
[2.3-announcement]: topics/2.3-announcement.md
|
[2.3-announcement]: topics/2.3-announcement.md
|
||||||
|
[2.4-announcement]: topics/2.4-announcement.md
|
||||||
|
[kickstarter-announcement]: topics/kickstarter-announcement.md
|
||||||
[release-notes]: topics/release-notes.md
|
[release-notes]: topics/release-notes.md
|
||||||
[credits]: topics/credits.md
|
[credits]: topics/credits.md
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,21 @@
|
||||||
})();
|
})();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
<style>
|
||||||
|
span.fusion-wrap a {
|
||||||
|
display: block;
|
||||||
|
margin-top: 10px;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.fusion-poweredby {
|
||||||
|
display: block;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
div.promo {display: none;}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body onload="prettyPrint()" class="{{ page_id }}-page">
|
<body onload="prettyPrint()" class="{{ page_id }}-page">
|
||||||
|
|
||||||
|
@ -106,6 +121,8 @@
|
||||||
<li><a href="{{ base_url }}/topics/rest-framework-2-announcement{{ suffix }}">2.0 Announcement</a></li>
|
<li><a href="{{ base_url }}/topics/rest-framework-2-announcement{{ suffix }}">2.0 Announcement</a></li>
|
||||||
<li><a href="{{ base_url }}/topics/2.2-announcement{{ suffix }}">2.2 Announcement</a></li>
|
<li><a href="{{ base_url }}/topics/2.2-announcement{{ suffix }}">2.2 Announcement</a></li>
|
||||||
<li><a href="{{ base_url }}/topics/2.3-announcement{{ suffix }}">2.3 Announcement</a></li>
|
<li><a href="{{ base_url }}/topics/2.3-announcement{{ suffix }}">2.3 Announcement</a></li>
|
||||||
|
<li><a href="{{ base_url }}/topics/2.4-announcement{{ suffix }}">2.4 Announcement</a></li>
|
||||||
|
<li><a href="{{ base_url }}/topics/kickstarter-announcement{{ suffix }}">Kickstarter Announcement</a></li>
|
||||||
<li><a href="{{ base_url }}/topics/release-notes{{ suffix }}">Release Notes</a></li>
|
<li><a href="{{ base_url }}/topics/release-notes{{ suffix }}">Release Notes</a></li>
|
||||||
<li><a href="{{ base_url }}/topics/credits{{ suffix }}">Credits</a></li>
|
<li><a href="{{ base_url }}/topics/credits{{ suffix }}">Credits</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -169,11 +186,9 @@
|
||||||
<div id="table-of-contents">
|
<div id="table-of-contents">
|
||||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||||
{{ toc }}
|
{{ toc }}
|
||||||
<div>
|
<div class="promo">
|
||||||
|
{{ ad_block }}
|
||||||
{{ ad_block }}
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -199,6 +214,7 @@
|
||||||
<script src="{{ base_url }}/js/jquery-1.8.1-min.js"></script>
|
<script src="{{ base_url }}/js/jquery-1.8.1-min.js"></script>
|
||||||
<script src="{{ base_url }}/js/prettify-1.0.js"></script>
|
<script src="{{ base_url }}/js/prettify-1.0.js"></script>
|
||||||
<script src="{{ base_url }}/js/bootstrap-2.1.1-min.js"></script>
|
<script src="{{ base_url }}/js/bootstrap-2.1.1-min.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
//$('.side-nav').scrollspy()
|
//$('.side-nav').scrollspy()
|
||||||
var shiftWindow = function() { scrollBy(0, -50) };
|
var shiftWindow = function() { scrollBy(0, -50) };
|
||||||
|
|
172
docs/topics/2.4-announcement.md
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
# REST framework 2.4 announcement
|
||||||
|
|
||||||
|
The 2.4 release is largely an intermediate step, tying up some outstanding issues prior to the 3.x series.
|
||||||
|
|
||||||
|
## Version requirements
|
||||||
|
|
||||||
|
Support for Django 1.3 has been dropped.
|
||||||
|
The lowest supported version of Django is now 1.4.2.
|
||||||
|
|
||||||
|
The current plan is for REST framework to remain in lockstep with [Django's long-term support policy][lts-releases].
|
||||||
|
|
||||||
|
## Django 1.7 support
|
||||||
|
|
||||||
|
The optional authtoken application now includes support for *both* Django 1.7 schema migrations, *and* for old-style `south` migrations.
|
||||||
|
|
||||||
|
**If you are using authtoken, and you want to continue using `south`, you must upgrade your `south` package to version 1.0.**
|
||||||
|
|
||||||
|
## Deprecation of `.model` view attribute
|
||||||
|
|
||||||
|
The `.model` attribute on view classes is an optional shortcut for either or both of `.serializer_class` and `.queryset`. Its usage results in more implicit, less obvious behavior.
|
||||||
|
|
||||||
|
The documentation has previously stated that usage of the more explicit style is prefered, and we're now taking that one step further and deprecating the usage of the `.model` shortcut.
|
||||||
|
|
||||||
|
Doing so will mean that there are cases of API code where you'll now need to include a serializer class where you previously were just using the `.model` shortcut. However we firmly believe that it is the right trade-off to make.
|
||||||
|
|
||||||
|
Removing the shortcut takes away an unneccessary layer of abstraction, and makes your codebase more explicit without any significant extra complexity. It also results in better consistency, as there's now only one way to set the serializer class and queryset attributes for the view, instead of two.
|
||||||
|
|
||||||
|
The `DEFAULT_MODEL_SERIALIZER_CLASS` API setting is now also deprecated.
|
||||||
|
|
||||||
|
## Updated test runner
|
||||||
|
|
||||||
|
We now have a new test runner for developing against the project,, that uses the excellent [py.test](http://pytest.org) library.
|
||||||
|
|
||||||
|
To use it make sure you have first installed the test requirements.
|
||||||
|
|
||||||
|
pip install -r requirements-test.txt
|
||||||
|
|
||||||
|
Then run the `runtests.py` script.
|
||||||
|
|
||||||
|
./runtests.py
|
||||||
|
|
||||||
|
The new test runner also includes [flake8](https://flake8.readthedocs.org) code linting, which should help keep our coding style consistent.
|
||||||
|
|
||||||
|
#### Test runner flags
|
||||||
|
|
||||||
|
Run using a more concise output style.
|
||||||
|
|
||||||
|
./runtests -q
|
||||||
|
|
||||||
|
Run the tests using a more concise output style, no coverage, no flake8.
|
||||||
|
|
||||||
|
./runtests --fast
|
||||||
|
|
||||||
|
Don't run the flake8 code linting.
|
||||||
|
|
||||||
|
./runtests --nolint
|
||||||
|
|
||||||
|
Only run the flake8 code linting, don't run the tests.
|
||||||
|
|
||||||
|
./runtests --lintonly
|
||||||
|
|
||||||
|
Run the tests for a given test case.
|
||||||
|
|
||||||
|
./runtests MyTestCase
|
||||||
|
|
||||||
|
Run the tests for a given test method.
|
||||||
|
|
||||||
|
./runtests MyTestCase.test_this_method
|
||||||
|
|
||||||
|
Shorter form to run the tests for a given test method.
|
||||||
|
|
||||||
|
./runtests test_this_method
|
||||||
|
|
||||||
|
Note: The test case and test method matching is fuzzy and will sometimes run other tests that contain a partial string match to the given command line input.
|
||||||
|
|
||||||
|
## Improved viewset routing
|
||||||
|
|
||||||
|
The `@action` and `@link` decorators were inflexible in that they only allowed additional routes to be added against instance style URLs, not against list style URLs.
|
||||||
|
|
||||||
|
The `@action` and `@link` decorators have now been moved to pending deprecation, and the `@list_route` and `@detail_route` decorators have been introduced.
|
||||||
|
|
||||||
|
Here's an example of using the new decorators. Firstly we have a detail-type route named "set_password" that acts on a single instance, and takes a `pk` argument in the URL. Secondly we have a list-type route named "recent_users" that acts on a queryset, and does not take any arguments in the URL.
|
||||||
|
|
||||||
|
class UserViewSet(viewsets.ModelViewSet):
|
||||||
|
"""
|
||||||
|
A viewset that provides the standard actions
|
||||||
|
"""
|
||||||
|
queryset = User.objects.all()
|
||||||
|
serializer_class = UserSerializer
|
||||||
|
|
||||||
|
@detail_route(methods=['post'])
|
||||||
|
def set_password(self, request, pk=None):
|
||||||
|
user = self.get_object()
|
||||||
|
serializer = PasswordSerializer(data=request.DATA)
|
||||||
|
if serializer.is_valid():
|
||||||
|
user.set_password(serializer.data['password'])
|
||||||
|
user.save()
|
||||||
|
return Response({'status': 'password set'})
|
||||||
|
else:
|
||||||
|
return Response(serializer.errors,
|
||||||
|
status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
@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)
|
||||||
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
For more details, see the [viewsets documentation](../api-guide/viewsets.md).
|
||||||
|
|
||||||
|
## Throttle behavior
|
||||||
|
|
||||||
|
There's one bugfix in 2.4 that's worth calling out, as it will *invalidate existing throttle caches* when you upgrade.
|
||||||
|
|
||||||
|
We've now fixed a typo on the `cache_format` attribute. Previously this was named `"throtte_%(scope)s_%(ident)s"`, it is now `"throttle_%(scope)s_%(ident)s"`.
|
||||||
|
|
||||||
|
If you're concerned about the invalidation you have two options.
|
||||||
|
|
||||||
|
* Manually pre-populate your cache with the fixed version.
|
||||||
|
* Set the `cache_format` attribute on your throttle class in order to retain the previous incorrect spelling.
|
||||||
|
|
||||||
|
## Other features
|
||||||
|
|
||||||
|
There are also a number of other features and bugfixes as [listed in the release notes][2-4-release-notes]. In particular these include:
|
||||||
|
|
||||||
|
[Customizable view name and description functions][view-name-and-description-settings] for use with the browsable API, by using the `VIEW_NAME_FUNCTION` and `VIEW_DESCRIPTION_FUNCTION` settings.
|
||||||
|
|
||||||
|
Smarter [client IP identification for throttling][client-ip-identification], with the addition of the `NUM_PROXIES` setting.
|
||||||
|
|
||||||
|
Added the standardized `Retry-After` header to throttled responses, as per [RFC 6585](http://tools.ietf.org/html/rfc6585). This should now be used in preference to the custom `X-Throttle-Wait-Seconds` header which will be fully deprecated in 3.0.
|
||||||
|
|
||||||
|
## Deprecations
|
||||||
|
|
||||||
|
All API changes in 2.3 that previously raised `PendingDeprecationWarning` will now raise a `DeprecationWarning`, which is loud by default.
|
||||||
|
|
||||||
|
All API changes in 2.3 that previously raised `DeprecationWarning` have now been removed entirely.
|
||||||
|
|
||||||
|
Furter details on these deprecations is available in the [2.3 announcement][2-3-announcement].
|
||||||
|
|
||||||
|
## Labels and milestones
|
||||||
|
|
||||||
|
Although not strictly part of the 2.4 release it's also worth noting here that we've been working hard towards improving our triage process.
|
||||||
|
|
||||||
|
The [labels that we use in GitHub][github-labels] have been cleaned up, and all existing tickets triaged. Any given ticket should have one and only one label, indicating its current state.
|
||||||
|
|
||||||
|
We've also [started using milestones][github-milestones] in order to track tickets against particular releases.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
**Above**: *Overview of our current use of labels and milestones in GitHub.*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
We hope both of these changes will help make the management process more clear and obvious and help keep tickets well-organised and relevant.
|
||||||
|
|
||||||
|
## Next steps
|
||||||
|
|
||||||
|
The next planned release will be 3.0, featuring an improved and simplified serializer implementation.
|
||||||
|
|
||||||
|
Once again, many thanks to all the generous [backers and sponsors][kickstarter-sponsors] who've helped make this possible!
|
||||||
|
|
||||||
|
[lts-releases]: https://docs.djangoproject.com/en/dev/internals/release-process/#long-term-support-lts-releases
|
||||||
|
[2-4-release-notes]: release-notes#240
|
||||||
|
[view-name-and-description-settings]: ../api-guide/settings/#view-names-and-descriptions
|
||||||
|
[client-ip-identification]: ../api-guide/throttling/#how-clients-are-identified
|
||||||
|
[2-3-announcement]: 2.3-announcement
|
||||||
|
[github-labels]: https://github.com/tomchristie/django-rest-framework/issues
|
||||||
|
[github-milestones]: https://github.com/tomchristie/django-rest-framework/milestones
|
||||||
|
[kickstarter-sponsors]: kickstarter-announcement#sponsors
|
|
@ -69,6 +69,7 @@ For more specific CSS tweaks than simply overriding the default bootstrap theme
|
||||||
|
|
||||||
All of the blocks available in the browsable API base template that can be used in your `api.html`.
|
All of the blocks available in the browsable API base template that can be used in your `api.html`.
|
||||||
|
|
||||||
|
* `body` - The entire html `<body>`.
|
||||||
* `bodyclass` - Class attribute for the `<body>` tag, empty by default.
|
* `bodyclass` - Class attribute for the `<body>` tag, empty by default.
|
||||||
* `bootstrap_theme` - CSS for the Bootstrap theme.
|
* `bootstrap_theme` - CSS for the Bootstrap theme.
|
||||||
* `bootstrap_navbar_variant` - CSS class for the navbar.
|
* `bootstrap_navbar_variant` - CSS class for the navbar.
|
||||||
|
@ -167,10 +168,10 @@ You can now add the `autocomplete_light.ChoiceWidget` widget to the serializer f
|
||||||
[bootstrap]: http://getbootstrap.com
|
[bootstrap]: http://getbootstrap.com
|
||||||
[cerulean]: ../img/cerulean.png
|
[cerulean]: ../img/cerulean.png
|
||||||
[slate]: ../img/slate.png
|
[slate]: ../img/slate.png
|
||||||
[bcustomize]: http://twitter.github.com/bootstrap/customize.html#variables
|
[bcustomize]: http://getbootstrap.com/2.3.2/customize.html
|
||||||
[bswatch]: http://bootswatch.com/
|
[bswatch]: http://bootswatch.com/
|
||||||
[bcomponents]: http://twitter.github.com/bootstrap/components.html
|
[bcomponents]: http://getbootstrap.com/2.3.2/components.html
|
||||||
[bcomponentsnav]: http://twitter.github.com/bootstrap/components.html#navbar
|
[bcomponentsnav]: http://getbootstrap.com/2.3.2/components.html#navbar
|
||||||
[autocomplete-packages]: https://www.djangopackages.com/grids/g/auto-complete/
|
[autocomplete-packages]: https://www.djangopackages.com/grids/g/auto-complete/
|
||||||
[django-autocomplete-light]: https://github.com/yourlabs/django-autocomplete-light
|
[django-autocomplete-light]: https://github.com/yourlabs/django-autocomplete-light
|
||||||
[django-autocomplete-light-install]: http://django-autocomplete-light.readthedocs.org/en/latest/#install
|
[django-autocomplete-light-install]: http://django-autocomplete-light.readthedocs.org/en/latest/#install
|
||||||
|
|
|
@ -62,10 +62,44 @@ To run the tests, clone the repository, and then:
|
||||||
virtualenv env
|
virtualenv env
|
||||||
source env/bin/activate
|
source env/bin/activate
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
pip install -r optionals.txt
|
pip install -r requirements-test.txt
|
||||||
|
|
||||||
# Run the tests
|
# Run the tests
|
||||||
rest_framework/runtests/runtests.py
|
./runtests.py
|
||||||
|
|
||||||
|
### Test options
|
||||||
|
|
||||||
|
Run using a more concise output style.
|
||||||
|
|
||||||
|
./runtests -q
|
||||||
|
|
||||||
|
Run the tests using a more concise output style, no coverage, no flake8.
|
||||||
|
|
||||||
|
./runtests --fast
|
||||||
|
|
||||||
|
Don't run the flake8 code linting.
|
||||||
|
|
||||||
|
./runtests --nolint
|
||||||
|
|
||||||
|
Only run the flake8 code linting, don't run the tests.
|
||||||
|
|
||||||
|
./runtests --lintonly
|
||||||
|
|
||||||
|
Run the tests for a given test case.
|
||||||
|
|
||||||
|
./runtests MyTestCase
|
||||||
|
|
||||||
|
Run the tests for a given test method.
|
||||||
|
|
||||||
|
./runtests MyTestCase.test_this_method
|
||||||
|
|
||||||
|
Shorter form to run the tests for a given test method.
|
||||||
|
|
||||||
|
./runtests test_this_method
|
||||||
|
|
||||||
|
Note: The test case and test method matching is fuzzy and will sometimes run other tests that contain a partial string match to the given command line input.
|
||||||
|
|
||||||
|
### Running against multiple environments
|
||||||
|
|
||||||
You can also use the excellent [tox][tox] testing tool to run the tests against all supported versions of Python and Django. Install `tox` globally, and then simply run:
|
You can also use the excellent [tox][tox] testing tool to run the tests against all supported versions of Python and Django. Install `tox` globally, and then simply run:
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ You can modify the response behavior to `OPTIONS` requests by overriding the `me
|
||||||
|
|
||||||
To be fully RESTful an API should present its available actions as hypermedia controls in the responses that it sends.
|
To be fully RESTful an API should present its available actions as hypermedia controls in the responses that it sends.
|
||||||
|
|
||||||
In this approach, rather than documenting the available API endpoints up front, the description instead concentrates on the *media types* that are used. The available actions take may be taken on any given URL are not strictly fixed, but are instead made available by the presence of link and form controls in the returned document.
|
In this approach, rather than documenting the available API endpoints up front, the description instead concentrates on the *media types* that are used. The available actions that may be taken on any given URL are not strictly fixed, but are instead made available by the presence of link and form controls in the returned document.
|
||||||
|
|
||||||
To implement a hypermedia API you'll need to decide on an appropriate media type for the API, and implement a custom renderer and parser for that media type. The [REST, Hypermedia & HATEOAS][hypermedia-docs] section of the documentation includes pointers to background reading, as well as links to various hypermedia formats.
|
To implement a hypermedia API you'll need to decide on an appropriate media type for the API, and implement a custom renderer and parser for that media type. The [REST, Hypermedia & HATEOAS][hypermedia-docs] section of the documentation includes pointers to background reading, as well as links to various hypermedia formats.
|
||||||
|
|
||||||
|
|
163
docs/topics/kickstarter-announcement.md
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
# Kickstarting Django REST framework 3
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<iframe width="480" height="360" src="https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3/widget/video.html" frameborder="0" scrolling="no"> </iframe>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
In order to continue to drive the project forward, I'm launching a Kickstarter campaign to help fund the development of a major new release - Django REST framework 3.
|
||||||
|
|
||||||
|
## Project details
|
||||||
|
|
||||||
|
This new release will allow us to comprehensively address some of the shortcomings of the framework, and will aim to include the following:
|
||||||
|
|
||||||
|
* Faster, simpler and easier-to-use serializers.
|
||||||
|
* An alternative admin-style interface for the browsable API.
|
||||||
|
* Search and filtering controls made accessible in the browsable API.
|
||||||
|
* Alternative API pagination styles.
|
||||||
|
* Documentation around API versioning.
|
||||||
|
* Triage of outstanding tickets.
|
||||||
|
* Improving the ongoing quality and maintainability of the project.
|
||||||
|
|
||||||
|
Full details are available now on the [project page](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3).
|
||||||
|
|
||||||
|
If you're interested in helping make sustainable open source development a reality please [visit the Kickstarter page](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3) and consider funding the project.
|
||||||
|
|
||||||
|
I can't wait to see where this takes us!
|
||||||
|
|
||||||
|
Many thanks to everyone for your support so far,
|
||||||
|
|
||||||
|
Tom Christie :)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sponsors
|
||||||
|
|
||||||
|
We've now blazed way past all our goals, with a staggering £30,000 (~$50,000), meaning I'll be in a position to work on the project significantly beyond what we'd originally planned for. I owe a huge debt of gratitude to all the wonderful companies and individuals who have been backing the project so generously, and making this possible.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Platinum sponsors
|
||||||
|
|
||||||
|
Our platinum sponsors have each made a hugely substantial contribution to the future development of Django REST framework, and I simply can't thank them enough.
|
||||||
|
|
||||||
|
<ul class="sponsor diamond">
|
||||||
|
<li><a href="https://www.eventbrite.com/" rel="nofollow" style="background-image:url(../img/sponsors/0-eventbrite.png);">Eventbrite</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="sponsor platinum">
|
||||||
|
<li><a href="https://www.divio.ch/" rel="nofollow" style="background-image:url(../img/sponsors/1-divio.png);">Divio</a></li>
|
||||||
|
<li><a href="http://company.onlulu.com/en/" rel="nofollow" style="background-image:url(../img/sponsors/1-lulu.png);">Lulu</a></li>
|
||||||
|
<li><a href="https://p.ota.to/" rel="nofollow" style="background-image:url(../img/sponsors/1-potato.png);">Potato</a></li>
|
||||||
|
<li><a href="http://www.wiredrive.com/" rel="nofollow" style="background-image:url(../img/sponsors/1-wiredrive.png);">Wiredrive</a></li>
|
||||||
|
<li><a href="http://www.cyaninc.com/" rel="nofollow" style="background-image:url(../img/sponsors/1-cyan.png);">Cyan</a></li>
|
||||||
|
<li><a href="https://www.runscope.com/" rel="nofollow" style="background-image:url(../img/sponsors/1-runscope.png);">Runscope</a></li>
|
||||||
|
<li><a href="http://simpleenergy.com/" rel="nofollow" style="background-image:url(../img/sponsors/1-simple-energy.png);">Simple Energy</a></li>
|
||||||
|
<li><a href="http://vokalinteractive.com/" rel="nofollow" style="background-image:url(../img/sponsors/1-vokal_interactive.png);">VOKAL Interactive</a></li>
|
||||||
|
<li><a href="http://www.purplebit.com/" rel="nofollow" style="background-image:url(../img/sponsors/1-purplebit.png);">Purple Bit</a></li>
|
||||||
|
<li><a href="http://www.kuwaitnet.net/" rel="nofollow" style="background-image:url(../img/sponsors/1-kuwaitnet.png);">KuwaitNET</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Gold sponsors
|
||||||
|
|
||||||
|
Our gold sponsors include companies large and small. Many thanks for their significant funding of the project and their commitment to sustainable open-source development.
|
||||||
|
|
||||||
|
<ul class="sponsor gold">
|
||||||
|
<li><a href="https://laterpay.net/" rel="nofollow" style="background-image:url(../img/sponsors/2-laterpay.png);">LaterPay</a></li>
|
||||||
|
<li><a href="https://www.schubergphilis.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-schuberg_philis.png);">Schuberg Philis</a></li>
|
||||||
|
<li><a href="http://prorenata.se/" rel="nofollow" style="background-image:url(../img/sponsors/2-prorenata.png);">ProReNata AB</a></li>
|
||||||
|
<li><a href="https://www.sgawebsites.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-sga.png);">SGA Websites</a></li>
|
||||||
|
<li><a href="http://www.sirono.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-sirono.png);">Sirono</a></li>
|
||||||
|
<li><a href="http://www.vinta.com.br/" rel="nofollow" style="background-image:url(../img/sponsors/2-vinta.png);">Vinta Software Studio</a></li>
|
||||||
|
<li><a href="http://www.rapasso.nl/index.php/en" rel="nofollow" style="background-image:url(../img/sponsors/2-rapasso.png);">Rapasso</a></li>
|
||||||
|
<li><a href="https://mirusresearch.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-mirus_research.png);">Mirus Research</a></li>
|
||||||
|
<li><a href="http://hipolabs.com" rel="nofollow" style="background-image:url(../img/sponsors/2-hipo.png);">Hipo</a></li>
|
||||||
|
<li><a href="http://www.byte.nl" rel="nofollow" style="background-image:url(../img/sponsors/2-byte.png);">Byte</a></li>
|
||||||
|
<li><a href="http://lightningkite.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-lightning_kite.png);">Lightning Kite</a></li>
|
||||||
|
<li><a href="https://opbeat.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-opbeat.png);">Opbeat</a></li>
|
||||||
|
<li><a href="https://koordinates.com" rel="nofollow" style="background-image:url(../img/sponsors/2-koordinates.png);">Koordinates</a></li>
|
||||||
|
<li><a href="http://pulsecode.ca" rel="nofollow" style="background-image:url(../img/sponsors/2-pulsecode.png);">Pulsecode Inc.</a></li>
|
||||||
|
<li><a href="http://singinghorsestudio.com" rel="nofollow" style="background-image:url(../img/sponsors/2-singing-horse.png);">Singing Horse Studio Ltd.</a></li>
|
||||||
|
<li><a href="https://www.heroku.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-heroku.png);">Heroku</a></li>
|
||||||
|
<li><a href="https://www.galileo-press.de/" rel="nofollow" style="background-image:url(../img/sponsors/2-galileo_press.png);">Galileo Press</a></li>
|
||||||
|
<li><a href="http://www.securitycompass.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-security_compass.png);">Security Compass</a></li>
|
||||||
|
<li><a href="https://www.djangoproject.com/foundation/" rel="nofollow" style="background-image:url(../img/sponsors/2-django.png);">Django Software Foundation</a></li>
|
||||||
|
<li><a href="http://www.hipflaskapp.com" rel="nofollow" style="background-image:url(../img/sponsors/2-hipflask.png);">Hipflask</a></li>
|
||||||
|
<li><a href="http://www.crate.io/" rel="nofollow" style="background-image:url(../img/sponsors/2-crate.png);">Crate</a></li>
|
||||||
|
<li><a href="http://crypticocorp.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-cryptico.png);">Cryptico Corp</a></li>
|
||||||
|
<li><a href="http://www.nexthub.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-nexthub.png);">NextHub</a></li>
|
||||||
|
<li><a href="https://www.compile.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-compile.png);">Compile</a></li>
|
||||||
|
<li><a href="http://wusawork.org" rel="nofollow" style="background-image:url(../img/sponsors/2-wusawork.png);">WusaWork</a></li>
|
||||||
|
<li><a href="http://envisionlinux.org/blog" rel="nofollow">Envision Linux</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div style="clear: both; padding-bottom: 40px;"></div>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Silver sponsors
|
||||||
|
|
||||||
|
The serious financial contribution that our silver sponsors have made is very much appreciated. I'd like to say a particular thank you to individuals who have choosen to privately support the project at this level.
|
||||||
|
|
||||||
|
<ul class="sponsor silver">
|
||||||
|
<li><a href="http://www.imtapps.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-imt_computer_services.png);">IMT Computer Services</a></li>
|
||||||
|
<li><a href="http://wildfish.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-wildfish.png);">Wildfish</a></li>
|
||||||
|
<li><a href="http://www.thermondo.de/" rel="nofollow" style="background-image:url(../img/sponsors/3-thermondo-gmbh.png);">Thermondo GmbH</a></li>
|
||||||
|
<li><a href="http://providenz.fr/" rel="nofollow" style="background-image:url(../img/sponsors/3-providenz.png);">Providenz</a></li>
|
||||||
|
<li><a href="https://www.alwaysdata.com" rel="nofollow" style="background-image:url(../img/sponsors/3-alwaysdata.png);">alwaysdata.com</a></li>
|
||||||
|
<li><a href="http://www.triggeredmessaging.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-triggered_messaging.png);">Triggered Messaging</a></li>
|
||||||
|
<li><a href="https://www.ipushpull.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-ipushpull.png);">PushPull Technology Ltd</a></li>
|
||||||
|
<li><a href="http://www.transcode.de/" rel="nofollow" style="background-image:url(../img/sponsors/3-transcode.png);">Transcode</a></li>
|
||||||
|
<li><a href="https://garfo.io/" rel="nofollow" style="background-image:url(../img/sponsors/3-garfo.png);">Garfo</a></li>
|
||||||
|
<li><a href="https://goshippo.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-shippo.png);">Shippo</a></li>
|
||||||
|
<li><a href="http://www.gizmag.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-gizmag.png);">Gizmag</a></li>
|
||||||
|
<li><a href="http://www.tivix.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-tivix.png);">Tivix</a></li>
|
||||||
|
<li><a href="http://www.safaribooksonline.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-safari.png);">Safari</a></li>
|
||||||
|
<li><a href="http://brightloop.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-brightloop.png);">Bright Loop</a></li>
|
||||||
|
<li><a href="http://www.aba-systems.com.au/" rel="nofollow" style="background-image:url(../img/sponsors/3-aba.png);">ABA Systems</a></li>
|
||||||
|
<li><a href="http://beefarm.ru/" rel="nofollow" style="background-image:url(../img/sponsors/3-beefarm.png);">beefarm.ru</a></li>
|
||||||
|
<li><a href="http://www.vzzual.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-vzzual.png);">Vzzual.com</a></li>
|
||||||
|
<li><a href="http://infinite-code.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-infinite_code.png);">Infinite Code</a></li>
|
||||||
|
<li><a href="http://crosswordtracker.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-crosswordtracker.png);">Crossword Tracker</a></li>
|
||||||
|
<li><a href="https://www.pkgfarm.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-pkgfarm.png);">PkgFarm</a></li>
|
||||||
|
<li><a href="http://life.tl/" rel="nofollow" style="background-image:url(../img/sponsors/3-life_the_game.png);">Life. The Game.</a></li>
|
||||||
|
<li><a href="http://blimp.io/" rel="nofollow" style="background-image:url(../img/sponsors/3-blimp.png);">Blimp</a></li>
|
||||||
|
<li><a href="http://pathwright.com" rel="nofollow" style="background-image:url(../img/sponsors/3-pathwright.png);">Pathwright</a></li>
|
||||||
|
<li><a href="http://fluxility.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-fluxility.png);">Fluxility</a></li>
|
||||||
|
<li><a href="http://teonite.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-teonite.png);">Teonite</a></li>
|
||||||
|
<li><a href="http://trackmaven.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-trackmaven.png);">TrackMaven</a></li>
|
||||||
|
<li><a href="http://www.phurba.net/" rel="nofollow" style="background-image:url(../img/sponsors/3-phurba.png);">Phurba</a></li>
|
||||||
|
<li><a href="http://www.nephila.co.uk/" rel="nofollow" style="background-image:url(../img/sponsors/3-nephila.png);">Nephila</a></li>
|
||||||
|
<li><a href="http://www.aditium.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-aditium.png);">Aditium</a></li>
|
||||||
|
<li><a href="http://www.eyesopen.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-openeye.png);">OpenEye Scientific Software</a></li>
|
||||||
|
<li><a href="https://holvi.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-holvi.png);">Holvi</a></li>
|
||||||
|
<li><a href="http://cantemo.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-cantemo.gif);">Cantemo</a></li>
|
||||||
|
<li><a href="https://www.makespace.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-makespace.png);">MakeSpace</a></li>
|
||||||
|
<li><a href="https://www.ax-semantics.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-ax_semantics.png);">AX Semantics</a></li>
|
||||||
|
<li><a href="http://istrategylabs.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-isl.png);">ISL</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div style="clear: both; padding-bottom: 40px;"></div>
|
||||||
|
|
||||||
|
**Individual backers**: Paul Hallett, <a href="http://www.paulwhippconsulting.com/">Paul Whipp</a>, Dylan Roy, Jannis Leidel, <a href="https://linovia.com/en/">Xavier Ordoquy</a>, <a href="http://spielmannsolutions.com/">Johannes Spielmann</a>, <a href="http://brooklynhacker.com/">Rob Spectre</a>, <a href="http://chrisheisel.com/">Chris Heisel</a>, Marwan Alsabbagh, Haris Ali, Tuomas Toivonen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Advocates
|
||||||
|
|
||||||
|
The following individuals made a significant financial contribution to the development of Django REST framework 3, for which I can only offer a huge, warm and sincere thank you!
|
||||||
|
|
||||||
|
**Individual backers**: Jure Cuhalev, Kevin Brolly, Ferenc Szalai, Dougal Matthews, Stefan Foulis, Carlos Hernando, Alen Mujezinovic, Ross Crawford-d'Heureuse, George Kappel, Alasdair Nicol, John Carr, Steve Winton, Trey, Manuel Miranda, David Horn, Vince Mi, Daniel Sears, Jamie Matthews, Ryan Currah, Marty Kemka, Scott Nixon, Moshin Elahi, Kevin Campbell, Jose Antonio Leiva Izquierdo, Kevin Stone, Andrew Godwin, Tijs Teulings, Roger Boardman, Xavier Antoviaque, Darian Moody, Lujeni, Jon Dugan, Wiley Kestner, Daniel C. Silverstein, Daniel Hahler, Subodh Nijsure, Philipp Weidenhiller, Yusuke Muraoka, Danny Roa, Reto Aebersold, Kyle Getrost, Décébal Hormuz, James Dacosta, Matt Long, Mauro Rocco, Tyrel Souza, Ryan Campbell, Ville Jyrkkä, Charalampos Papaloizou, Nikolai Røed Kristiansen, Antoni Aloy López, Celia Oakley, Michał Krawczak, Ivan VenOsdel, Tim Watts, Martin Warne, Nicola Jordan, Ryan Kaskel.
|
||||||
|
|
||||||
|
**Corporate backers**: Savannah Informatics, Prism Skylabs, Musical Operating Devices.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Supporters
|
||||||
|
|
||||||
|
There were also almost 300 further individuals choosing to help fund the project at other levels or choosing to give anonymously. Again, thank you, thank you, thank you!
|
|
@ -38,8 +38,75 @@ You can determine your currently installed version using `pip freeze`:
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2.4.x series
|
||||||
|
|
||||||
|
### 2.4.2
|
||||||
|
|
||||||
|
**Date**: 3rd September 2014
|
||||||
|
|
||||||
|
* Bugfix: Fix broken pagination for 2.4.x series.
|
||||||
|
|
||||||
|
### 2.4.1
|
||||||
|
|
||||||
|
**Date**: 1st September 2014
|
||||||
|
|
||||||
|
* Bugfix: Fix broken login template for browsable API.
|
||||||
|
|
||||||
|
### 2.4.0
|
||||||
|
|
||||||
|
**Date**: 29th August 2014
|
||||||
|
|
||||||
|
**Django version requirements**: The lowest supported version of Django is now 1.4.2.
|
||||||
|
|
||||||
|
**South version requirements**: This note applies to any users using the optional `authtoken` application, which includes an associated database migration. You must now *either* upgrade your `south` package to version 1.0, *or* instead use the built-in migration support available with Django 1.7.
|
||||||
|
|
||||||
|
* Added compatibility with Django 1.7's database migration support.
|
||||||
|
* New test runner, using `py.test`.
|
||||||
|
* Deprecated `.model` view attribute in favor of explicit `.queryset` and `.serializer_class` attributes. The `DEFAULT_MODEL_SERIALIZER_CLASS` setting is also deprecated.
|
||||||
|
* `@detail_route` and `@list_route` decorators replace `@action` and `@link`.
|
||||||
|
* Support customizable view name and description functions, using the `VIEW_NAME_FUNCTION` and `VIEW_DESCRIPTION_FUNCTION` settings.
|
||||||
|
* Added `NUM_PROXIES` setting for smarter client IP identification.
|
||||||
|
* Added `MAX_PAGINATE_BY` setting and `max_paginate_by` generic view attribute.
|
||||||
|
* Added `Retry-After` header to throttled responses, as per [RFC 6585](http://tools.ietf.org/html/rfc6585). This should now be used in preference to the custom `X-Trottle-Wait-Seconds` header which will be fully deprecated in 3.0.
|
||||||
|
* Added `cache` attribute to throttles to allow overriding of default cache.
|
||||||
|
* Added `lookup_value_regex` attribute to routers, to allow the URL argument matching to be constrainted by the user.
|
||||||
|
* Added `allow_none` option to `CharField`.
|
||||||
|
* Support Django's standard `status_code` class attribute on responses.
|
||||||
|
* More intuitive behavior on the test client, as `client.logout()` now also removes any credentials that have been set.
|
||||||
|
* Bugfix: `?page_size=0` query parameter now falls back to default page size for view, instead of always turning pagination off.
|
||||||
|
* Bugfix: Always uppercase `X-Http-Method-Override` methods.
|
||||||
|
* Bugfix: Copy `filter_backends` list before returning it, in order to prevent view code from mutating the class attribute itself.
|
||||||
|
* Bugfix: Set the `.action` attribute on viewsets when introspected by `OPTIONS` for testing permissions on the view.
|
||||||
|
* Bugfix: Ensure `ValueError` raised during deserialization results in a error list rather than a single error. This is now consistent with other validation errors.
|
||||||
|
* Bugfix: Fix `cache_format` typo on throttle classes, was `"throtte_%(scope)s_%(ident)s"`. Note that this will invalidate existing throttle caches.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 2.3.x series
|
## 2.3.x series
|
||||||
|
|
||||||
|
### 2.3.14
|
||||||
|
|
||||||
|
**Date**: 12th June 2014
|
||||||
|
|
||||||
|
* **Security fix**: Escape request path when it is include as part of the login and logout links in the browsable API.
|
||||||
|
* `help_text` and `verbose_name` automatically set for related fields on `ModelSerializer`.
|
||||||
|
* Fix nested serializers linked through a backward foreign key relation.
|
||||||
|
* Fix bad links for the `BrowsableAPIRenderer` with `YAMLRenderer`.
|
||||||
|
* Add `UnicodeYAMLRenderer` that extends `YAMLRenderer` with unicode.
|
||||||
|
* Fix `parse_header` argument convertion.
|
||||||
|
* Fix mediatype detection under Python 3.
|
||||||
|
* Web browseable API now offers blank option on dropdown when the field is not required.
|
||||||
|
* `APIException` representation improved for logging purposes.
|
||||||
|
* Allow source="*" within nested serializers.
|
||||||
|
* Better support for custom oauth2 provider backends.
|
||||||
|
* Fix field validation if it's optional and has no value.
|
||||||
|
* Add `SEARCH_PARAM` and `ORDERING_PARAM`.
|
||||||
|
* Fix `APIRequestFactory` to support arguments within the url string for GET.
|
||||||
|
* Allow three transport modes for access tokens when accessing a protected resource.
|
||||||
|
* Fix `QueryDict` encoding on request objects.
|
||||||
|
* Ensure throttle keys do not contain spaces, as those are invalid if using `memcached`.
|
||||||
|
* Support `blank_display_value` on `ChoiceField`.
|
||||||
|
|
||||||
### 2.3.13
|
### 2.3.13
|
||||||
|
|
||||||
**Date**: 6th March 2014
|
**Date**: 6th March 2014
|
||||||
|
@ -112,11 +179,11 @@ You can determine your currently installed version using `pip freeze`:
|
||||||
* Bugfix: `client.force_authenticate(None)` should also clear session info if it exists.
|
* Bugfix: `client.force_authenticate(None)` should also clear session info if it exists.
|
||||||
* Bugfix: Client sending empty string instead of file now clears `FileField`.
|
* Bugfix: Client sending empty string instead of file now clears `FileField`.
|
||||||
* Bugfix: Empty values on ChoiceFields with `required=False` now consistently return `None`.
|
* Bugfix: Empty values on ChoiceFields with `required=False` now consistently return `None`.
|
||||||
* Bugfix: Clients setting `page=0` now simply returns the default page size, instead of disabling pagination. [*]
|
* Bugfix: Clients setting `page_size=0` now simply returns the default page size, instead of disabling pagination. [*]
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[*] Note that the change in `page=0` behaviour fixes what is considered to be a bug in how clients can effect the pagination size. However if you were relying on this behavior you will need to add the following mixin to your list views in order to preserve the existing behavior.
|
[*] Note that the change in `page_size=0` behaviour fixes what is considered to be a bug in how clients can effect the pagination size. However if you were relying on this behavior you will need to add the following mixin to your list views in order to preserve the existing behavior.
|
||||||
|
|
||||||
class DisablePaginationMixin(object):
|
class DisablePaginationMixin(object):
|
||||||
def get_paginate_by(self, queryset=None):
|
def get_paginate_by(self, queryset=None):
|
||||||
|
|
|
@ -104,7 +104,7 @@ Don't forget to sync the database for the first time.
|
||||||
|
|
||||||
## Creating a Serializer class
|
## Creating a Serializer class
|
||||||
|
|
||||||
The first thing we need to get started on our Web API is 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.
|
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 django.forms import widgets
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
@ -143,7 +143,7 @@ The first thing we need to get started on our Web API is provide a way of serial
|
||||||
# Create new instance
|
# Create new instance
|
||||||
return Snippet(**attrs)
|
return Snippet(**attrs)
|
||||||
|
|
||||||
The first part of serializer class defines the fields that get serialized/deserialized. The `restore_object` method defines how fully fledged instances get created when deserializing data.
|
The first part of the serializer class defines the fields that get serialized/deserialized. The `restore_object` method defines how fully fledged instances get created when deserializing data.
|
||||||
|
|
||||||
Notice that we can also use various attributes that would typically be used on form fields, such as `widget=widgets.Textarea`. These can be used to control how the serializer should render when displayed as an HTML form. This is particularly useful for controlling how the browsable API should be displayed, as we'll see later in the tutorial.
|
Notice that we can also use various attributes that would typically be used on form fields, such as `widget=widgets.Textarea`. These can be used to control how the serializer should render when displayed as an HTML form. This is particularly useful for controlling how the browsable API should be displayed, as we'll see later in the tutorial.
|
||||||
|
|
||||||
|
|
|
@ -44,11 +44,11 @@ When that's all done we'll need to update our database tables.
|
||||||
Normally we'd create a database migration in order to do that, but for the purposes of this tutorial, let's just delete the database and start again.
|
Normally we'd create a database migration in order to do that, but for the purposes of this tutorial, let's just delete the database and start again.
|
||||||
|
|
||||||
rm tmp.db
|
rm tmp.db
|
||||||
python ./manage.py syncdb
|
python manage.py syncdb
|
||||||
|
|
||||||
You might also want to create a few different users, to use for testing the API. The quickest way to do this will be with the `createsuperuser` command.
|
You might also want to create a few different users, to use for testing the API. The quickest way to do this will be with the `createsuperuser` command.
|
||||||
|
|
||||||
python ./manage.py createsuperuser
|
python manage.py createsuperuser
|
||||||
|
|
||||||
## Adding endpoints for our User models
|
## Adding endpoints for our User models
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ Then, add the following property to **both** the `SnippetList` and `SnippetDetai
|
||||||
|
|
||||||
If you open a browser and navigate to the browsable API at the moment, you'll find that you're no longer able to create new code snippets. In order to do so we'd need to be able to login as a user.
|
If you open a browser and navigate to the browsable API at the moment, you'll find that you're no longer able to create new code snippets. In order to do so we'd need to be able to login as a user.
|
||||||
|
|
||||||
We can add a login view for use with the browsable API, by editing the URLconf in our project-level urls.py file.
|
We can add a login view for use with the browsable API, by editing the URLconf in our project-level `urls.py` file.
|
||||||
|
|
||||||
Add the following import at the top of the file:
|
Add the following import at the top of the file:
|
||||||
|
|
||||||
|
|