mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-23 01:57:00 +03:00
Simplifying bits of docs
This commit is contained in:
parent
387250bee4
commit
74beaefd12
56
README.md
56
README.md
|
@ -42,39 +42,10 @@ Add `'rest_framework'` to your `INSTALLED_APPS` setting.
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
)
|
)
|
||||||
|
|
||||||
If you're intending to use the browseable API you'll probably also want to add REST framework's login and logout views. Add the following to your root `urls.py` file.
|
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
|
||||||
...
|
|
||||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
|
||||||
)
|
|
||||||
|
|
||||||
Note that the URL path can be whatever you want, but you must include `'rest_framework.urls'` with the `'rest_framework'` namespace.
|
|
||||||
|
|
||||||
# Example
|
# Example
|
||||||
|
|
||||||
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 for accessing users and groups.
|
||||||
|
|
||||||
We'll create a read-write API for accessing users and groups.
|
|
||||||
|
|
||||||
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 = {
|
|
||||||
# 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,
|
|
||||||
# or allow read-only access for unauthenticated users.
|
|
||||||
'DEFAULT_PERMISSION_CLASSES': [
|
|
||||||
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
Don't forget to make sure you've also added `rest_framework` to your `INSTALLED_APPS`.
|
|
||||||
|
|
||||||
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.defaults import url, patterns, include
|
from django.conf.urls.defaults import url, patterns, include
|
||||||
|
@ -91,8 +62,8 @@ Here's our project's root `urls.py` module:
|
||||||
|
|
||||||
# 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', views.UserViewSet, name='user')
|
router.register(r'users', views.UserViewSet)
|
||||||
router.register(r'groups', views.GroupViewSet, name='group')
|
router.register(r'groups', views.GroupViewSet)
|
||||||
|
|
||||||
|
|
||||||
# Wire up our API using automatic URL routing.
|
# Wire up our API using automatic URL routing.
|
||||||
|
@ -102,6 +73,27 @@ Here's our project's root `urls.py` module:
|
||||||
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.
|
||||||
|
|
||||||
|
Add the following to your `settings.py` module:
|
||||||
|
|
||||||
|
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,
|
||||||
|
# or allow read-only access for unauthenticated users.
|
||||||
|
'DEFAULT_PERMISSION_CLASSES': [
|
||||||
|
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Don't forget to make sure you've also added `rest_framework` to your `INSTALLED_APPS` setting.
|
||||||
|
|
||||||
|
That's it, we're done!
|
||||||
|
|
||||||
# Documentation & Support
|
# Documentation & Support
|
||||||
|
|
||||||
Full documentation for the project is available at [http://django-rest-framework.org][docs].
|
Full documentation for the project is available at [http://django-rest-framework.org][docs].
|
||||||
|
|
|
@ -62,6 +62,10 @@ The following attributes control the basic view behavior.
|
||||||
* `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 field that should be used to lookup individual model instances. Defaults to `'pk'`. The URL conf should include a keyword argument corresponding to this value. More complex lookup styles can be supported by overriding the `get_object()` method.
|
* `lookup_field` - The field that should be used to lookup individual model instances. Defaults to `'pk'`. The URL conf should include a keyword argument corresponding to this value. More complex lookup styles can be supported by overriding the `get_object()` method.
|
||||||
|
|
||||||
|
**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.
|
||||||
|
|
||||||
**Pagination**:
|
**Pagination**:
|
||||||
|
|
||||||
The following attibutes are used to control pagination when used with list views.
|
The following attibutes are used to control pagination when used with list views.
|
||||||
|
@ -75,7 +79,6 @@ The following attibutes are used to control pagination when used with list views
|
||||||
|
|
||||||
* `filter_backend` - The filter backend class that should be used for filtering the queryset. Defaults to the same value as the `FILTER_BACKEND` setting.
|
* `filter_backend` - The filter backend class that should be used for filtering the queryset. Defaults to the same value as the `FILTER_BACKEND` setting.
|
||||||
* `allow_empty` - Determines if an empty list should successfully display zero results, or return a 404 response. Defaults to `True`, meaning empty lists will return sucessful `200 OK` responses, with zero results.
|
* `allow_empty` - Determines if an empty list should successfully display zero results, or return a 404 response. Defaults to `True`, meaning empty lists will return sucessful `200 OK` responses, with zero results.
|
||||||
* `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.
|
|
||||||
|
|
||||||
### Methods
|
### Methods
|
||||||
|
|
||||||
|
@ -160,7 +163,7 @@ The following classes are the concrete generic views. If you're using generic v
|
||||||
|
|
||||||
Used for **create-only** endpoints.
|
Used for **create-only** endpoints.
|
||||||
|
|
||||||
Provides `post` method handlers.
|
Provides a `post` method handler.
|
||||||
|
|
||||||
Extends: [GenericAPIView], [CreateModelMixin]
|
Extends: [GenericAPIView], [CreateModelMixin]
|
||||||
|
|
||||||
|
|
|
@ -15,15 +15,18 @@ REST framework adds support for automatic URL routing to Django, and provides yo
|
||||||
Here's an example of a simple URL conf, that uses `DefaultRouter`.
|
Here's an example of a simple URL conf, that uses `DefaultRouter`.
|
||||||
|
|
||||||
router = routers.SimpleRouter()
|
router = routers.SimpleRouter()
|
||||||
router.register(r'users', UserViewSet, name='user')
|
router.register(r'users', UserViewSet)
|
||||||
router.register(r'accounts', AccountViewSet, name='account')
|
router.register(r'accounts', AccountViewSet)
|
||||||
urlpatterns = router.urls
|
urlpatterns = router.urls
|
||||||
|
|
||||||
There are three arguments to the `register()` method:
|
There are two mandatory arguments to the `register()` method:
|
||||||
|
|
||||||
* `prefix` - The URL prefix to use for this set of routes.
|
* `prefix` - The URL prefix to use for this set of routes.
|
||||||
* `viewset` - The viewset class.
|
* `viewset` - The viewset class.
|
||||||
* `name` - The base to use for the URL names that are created.
|
|
||||||
|
Optionally, you may also specify an additional argument:
|
||||||
|
|
||||||
|
* `base_name` - The base to use for the URL names that are created. If unset the basename will be automatically generated based on the `model` or `queryset` attribute on the viewset, if it has one.
|
||||||
|
|
||||||
The example above would generate the following URL patterns:
|
The example above would generate the following URL patterns:
|
||||||
|
|
||||||
|
@ -101,6 +104,8 @@ The following example will only route to the `list` and `retrieve` actions, and
|
||||||
|
|
||||||
## Advanced custom routers
|
## Advanced custom routers
|
||||||
|
|
||||||
If you want to provide totally custom behavior, you can override `BaseRouter` and override the `get_urls()` method. The method should insect the registered viewsets and return a list of URL patterns. The registered prefix, viewset and basename tuples may be inspected by accessing the `self.registry` attribute.
|
If you want to provide totally custom behavior, you can override `BaseRouter` and override the `get_urls(self)` method. The method should insect the registered viewsets and return a list of URL patterns. The registered prefix, viewset and basename tuples may be inspected by accessing the `self.registry` attribute.
|
||||||
|
|
||||||
|
You may also want to override the `get_default_base_name(self, viewset)` method, or else always explicitly set the `base_name` argument when registering your viewsets with the router.
|
||||||
|
|
||||||
[cite]: http://guides.rubyonrails.org/routing.html
|
[cite]: http://guides.rubyonrails.org/routing.html
|
||||||
|
|
|
@ -42,7 +42,7 @@ If we need to, we can bind this viewset into two seperate views, like so:
|
||||||
Typically we wouldn't do this, but would instead register the viewset with a router, and allow the urlconf to be automatically generated.
|
Typically we wouldn't do this, but would instead register the viewset with a router, and allow the urlconf to be automatically generated.
|
||||||
|
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
router.register(r'users', UserViewSet, name='user')
|
router.register(r'users', UserViewSet)
|
||||||
urlpatterns = router.urls
|
urlpatterns = router.urls
|
||||||
|
|
||||||
Rather than writing your own viewsets, you'll often want to use the existing base classes that provide a default set of behavior. For example:
|
Rather than writing your own viewsets, you'll often want to use the existing base classes that provide a default set of behavior. For example:
|
||||||
|
|
|
@ -113,8 +113,8 @@ Here's our project's root `urls.py` module:
|
||||||
|
|
||||||
# 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', views.UserViewSet, name='user')
|
router.register(r'users', views.UserViewSet)
|
||||||
router.register(r'groups', views.GroupViewSet, name='group')
|
router.register(r'groups', views.GroupViewSet)
|
||||||
|
|
||||||
|
|
||||||
# Wire up our API using automatic URL routing.
|
# Wire up our API using automatic URL routing.
|
||||||
|
|
|
@ -105,8 +105,8 @@ Here's our re-wired `urls.py` file.
|
||||||
|
|
||||||
# Create a router and register our viewsets with it.
|
# Create a router and register our viewsets with it.
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
router.register(r'snippets', views.SnippetViewSet, name='snippet')
|
router.register(r'snippets', views.SnippetViewSet)
|
||||||
router.register(r'users', views.UserViewSet, name='user')
|
router.register(r'users', views.UserViewSet)
|
||||||
|
|
||||||
# The API URLs are now determined automatically by the router.
|
# The API URLs are now determined automatically by the router.
|
||||||
# Additionally, we include the login URLs for the browseable API.
|
# Additionally, we include the login URLs for the browseable API.
|
||||||
|
@ -115,7 +115,7 @@ Here's our re-wired `urls.py` file.
|
||||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
||||||
)
|
)
|
||||||
|
|
||||||
Registering the viewsets with the router is similar to providing a urlpattern. We include three arguments - the URL prefix for the views, the viewset itself, and the base name that should be used for constructing the URL names, such as `snippet-list`.
|
Registering the viewsets with the router is similar to providing a urlpattern. We include two arguments - the URL prefix for the views, and the viewset itself.
|
||||||
|
|
||||||
The `DefaultRouter` class we're using also automatically creates the API root view for us, so we can now delete the `api_root` method from our `views` module.
|
The `DefaultRouter` class we're using also automatically creates the API root view for us, so we can now delete the `api_root` method from our `views` module.
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ Create a new Django project, and start a new app called `quickstart`. Once you'
|
||||||
|
|
||||||
First up we're going to define some serializers in `quickstart/serializers.py` that we'll use for our data representations.
|
First up we're going to define some serializers in `quickstart/serializers.py` that we'll use for our data representations.
|
||||||
|
|
||||||
from django.contrib.auth.models import User, Group, Permission
|
from django.contrib.auth.models import User, Group
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,109 +19,64 @@ First up we're going to define some serializers in `quickstart/serializers.py` t
|
||||||
|
|
||||||
|
|
||||||
class GroupSerializer(serializers.HyperlinkedModelSerializer):
|
class GroupSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
permissions = serializers.ManySlugRelatedField(
|
|
||||||
slug_field='codename',
|
|
||||||
queryset=Permission.objects.all()
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Group
|
model = Group
|
||||||
fields = ('url', 'name', 'permissions')
|
fields = ('url', 'name')
|
||||||
|
|
||||||
Notice that we're using hyperlinked relations in this case, with `HyperlinkedModelSerializer`. You can also use primary key and various other relationships, but hyperlinking is good RESTful design.
|
Notice that we're using hyperlinked relations in this case, with `HyperlinkedModelSerializer`. You can also use primary key and various other relationships, but hyperlinking is good RESTful design.
|
||||||
|
|
||||||
We've also overridden the `permission` field on the `GroupSerializer`. In this case we don't want to use a hyperlinked representation, but instead use the list of permission codenames associated with the group, so we've used a `ManySlugRelatedField`, using the `codename` field for the representation.
|
|
||||||
|
|
||||||
## Views
|
## Views
|
||||||
|
|
||||||
Right, we'd better write some views then. Open `quickstart/views.py` and get typing.
|
Right, we'd better write some views then. Open `quickstart/views.py` and get typing.
|
||||||
|
|
||||||
from django.contrib.auth.models import User, Group
|
from django.contrib.auth.models import User, Group
|
||||||
from rest_framework import generics
|
from rest_framework import viewsets
|
||||||
from rest_framework.decorators import api_view
|
|
||||||
from rest_framework.reverse import reverse
|
|
||||||
from rest_framework.response import Response
|
|
||||||
from quickstart.serializers import UserSerializer, GroupSerializer
|
from quickstart.serializers import UserSerializer, GroupSerializer
|
||||||
|
|
||||||
|
|
||||||
@api_view(['GET'])
|
class UserViewSet(viewsets.ModelViewSet):
|
||||||
def api_root(request, format=None):
|
|
||||||
"""
|
"""
|
||||||
The entry endpoint of our API.
|
API endpoint that allows users to be viewed or edited.
|
||||||
"""
|
"""
|
||||||
return Response({
|
queryset = User.objects.all()
|
||||||
'users': reverse('user-list', request=request),
|
|
||||||
'groups': reverse('group-list', request=request),
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
class UserList(generics.ListCreateAPIView):
|
|
||||||
"""
|
|
||||||
API endpoint that represents a list of users.
|
|
||||||
"""
|
|
||||||
model = User
|
|
||||||
serializer_class = UserSerializer
|
serializer_class = UserSerializer
|
||||||
|
|
||||||
|
|
||||||
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
|
class GroupViewSet(viewsets.ModelViewSet):
|
||||||
"""
|
"""
|
||||||
API endpoint that represents a single user.
|
API endpoint that allows groups to be viewed or edited.
|
||||||
"""
|
"""
|
||||||
model = User
|
queryset = Group.objects.all()
|
||||||
serializer_class = UserSerializer
|
|
||||||
|
|
||||||
|
|
||||||
class GroupList(generics.ListCreateAPIView):
|
|
||||||
"""
|
|
||||||
API endpoint that represents a list of groups.
|
|
||||||
"""
|
|
||||||
model = Group
|
|
||||||
serializer_class = GroupSerializer
|
serializer_class = GroupSerializer
|
||||||
|
|
||||||
|
Rather that write multiple views we're grouping together all the common behavior into classes called `ViewSets`.
|
||||||
|
|
||||||
class GroupDetail(generics.RetrieveUpdateDestroyAPIView):
|
We can easily break these down into individual views if we need to, but using viewsets keeps the view logic nicely organized as well as being very concise.
|
||||||
"""
|
|
||||||
API endpoint that represents a single group.
|
|
||||||
"""
|
|
||||||
model = Group
|
|
||||||
serializer_class = GroupSerializer
|
|
||||||
|
|
||||||
Let's take a moment to look at what we've done here before we move on. We have one function-based view representing the root of the API, and four class-based views which map to our database models, and specify which serializers should be used for representing that data. Pretty simple stuff.
|
|
||||||
|
|
||||||
## URLs
|
## URLs
|
||||||
|
|
||||||
Okay, let's wire this baby up. On to `quickstart/urls.py`...
|
Okay, now let's wire up the API URLs. On to `quickstart/urls.py`...
|
||||||
|
|
||||||
from django.conf.urls import patterns, url, include
|
from django.conf.urls import patterns, url, include
|
||||||
from rest_framework.urlpatterns import format_suffix_patterns
|
from rest_framework import routers
|
||||||
from quickstart.views import UserList, UserDetail, GroupList, GroupDetail
|
from quickstart import views
|
||||||
|
|
||||||
|
router = routers.DefaultRouter()
|
||||||
|
router.register(r'users', views.UserViewSet)
|
||||||
|
router.register(r'groups', views.GroupViewSet)
|
||||||
|
|
||||||
urlpatterns = patterns('quickstart.views',
|
# Wire up our API using automatic URL routing.
|
||||||
url(r'^$', 'api_root'),
|
# Additionally, we include login URLs for the browseable API.
|
||||||
url(r'^users/$', UserList.as_view(), name='user-list'),
|
urlpatterns = patterns('',
|
||||||
url(r'^users/(?P<pk>\d+)/$', UserDetail.as_view(), name='user-detail'),
|
url(r'^', include(router.urls)),
|
||||||
url(r'^groups/$', GroupList.as_view(), name='group-list'),
|
|
||||||
url(r'^groups/(?P<pk>\d+)/$', GroupDetail.as_view(), name='group-detail'),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# Format suffixes
|
|
||||||
urlpatterns = format_suffix_patterns(urlpatterns, allowed=['json', 'api'])
|
|
||||||
|
|
||||||
|
|
||||||
# Default login/logout views
|
|
||||||
urlpatterns += patterns('',
|
|
||||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
||||||
)
|
)
|
||||||
|
|
||||||
There's a few things worth noting here.
|
Because we're using viewsets instead of views, we can automatically generate the URL conf for our API, by simply registering the viewsets with a router class.
|
||||||
|
|
||||||
Firstly the names `user-detail` and `group-detail` are important. We're using the default hyperlinked relationships without explicitly specifying the view names, so we need to use names of the style `{modelname}-detail` to represent the model instance views.
|
Again, if we need more control over the API URLs we can simply drop down to using regular class based views, and writing the URL conf explicitly.
|
||||||
|
|
||||||
Secondly, we're modifying the urlpatterns using `format_suffix_patterns`, to append optional `.json` style suffixes to our URLs.
|
Note that we're also including default login and logout views for use with the browsable API. That's optional, but useful if your API requires authentication and you want to use the browseable API.
|
||||||
|
|
||||||
Finally, we're including default login and logout views for use with the browsable API. That's optional, but useful if your API requires authentication and you want to use the browseable API.
|
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user