django-rest-framework公式ドキュメント記録

27694 ワード

Tutorial 1:Serializationシーケンス化


インストール環境

pip install django
pip install djangorestframework
pip install pygments  # We'll be using this for the code highlighting

テスト環境の作成を開始


djangoプロジェクトの作成
django-admin.py startproject tutorial

プロジェクトにappを作成する
python manage.py startapp snippets
tutorial/settings.pyファイルでの変更:app(自分で作成したappとrest_framework)を宣言します.
INSTALLED_APPS = (
    ...
    'rest_framework',
    'snippets.apps.SnippetsConfig',
)

Modelモジュールの作成

snippets/models.pyファイルの変更:
from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles

LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted((item, item) for item in get_all_styles())


class Snippet(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=100, blank=True, default='')
    code = models.TextField()
    linenos = models.BooleanField(default=False)
    language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
    style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)

    class Meta:
        ordering = ('created',)

作成したModelは、対応するdbテーブルを作成し、データベースを更新します.
python manage.py makemigrations snippets
python manage.py migrate

Creating a Serializer classシーケンサクラスの作成

snippets appディレクトリの下にserializers.pyを作成します.
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES


class SnippetSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(required=False, allow_blank=True, max_length=100)
    code = serializers.CharField(style={'base_template': 'textarea.html'})
    linenos = serializers.BooleanField(required=False)
    language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
    style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')

    def create(self, validated_data):
        """
        Create and return a new `Snippet` instance, given the validated data.
        """
        return Snippet.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """
        Update and return an existing `Snippet` instance, given the validated data.
        """
        instance.title = validated_data.get('title', instance.title)
        instance.code = validated_data.get('code', instance.code)
        instance.linenos = validated_data.get('linenos', instance.linenos)
        instance.language = validated_data.get('language', instance.language)
        instance.style = validated_data.get('style', instance.style)
        instance.save()
        return instance

Working with Serializersシーケンサクラスの使用


shell python manageを開きます.py shell
モデルオブジェクトを作成し、データベースに保存します.
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser

snippet = Snippet(code='foo = "bar"
') snippet.save() snippet = Snippet(code='print "hello, world"
') snippet.save()

シーケンス化オブジェクト:modelオブジェクトをpython基本データ型に変換するmodelオブジェクト
serializer = SnippetSerializer(snippet)
serializer.data
# {'title': '', 'id': 3, 'code': 'create by new
', 'style': 'friendly', 'language': 'python', 'linenos': False}

python基本データをjsonにレンダリング
content = JSONRenderer().render(serializer.data)
content
# b'{"id":3,"title":"","code":"create by new\
","linenos":false,"language":"python","style":"friendly"}'

逆シーケンス化json-』object
from django.utils.six import BytesIO

stream = BytesIO(content)
data = JSONParser().parse(stream)

逆シーケンス化されたobjectをデータベースに保存します.
serializer = SnippetSerializer(data=data) # data   json->object       object
serializer.is_valid()
# True
serializer.validated_data
# OrderedDict([('title', ''), ('code', 'print "hello, world"
'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]) serializer.save() #

データのセットを検索するには、次の手順に従います.
serializer = SnippetSerializer(Snippet.objects.all(), many=True)
serializer.data
# [OrderedDict([('id', 1), ('title', u''), ('code', u'foo = "bar"
'), ('linenos', False), ('langua......

Using ModelSerializersモデルを使用してシーケンス化


元のsnippets/serializers.pyファイルの内容を次のように置き換えます.
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES

class SnippetSerializer(serializers.ModelSerializer):
    class Meta:
        model = Snippet
        fields = ('id', 'title', 'code', 'linenos', 'language', 'style')

これを使用する利点の1つは、serializerインスタンスのプロパティby printing its representationを直接見ることです.
python manage.py shell


from snippets.serializers import SnippetSerializer
serializer = SnippetSerializer()
print(repr(serializer))
# SnippetSerializer():
#    id = IntegerField(label='ID', read_only=True)
#    title = CharField(allow_blank=True, max_length=100, required=False)
#    code = CharField(style={'base_template': 'textarea.html'})
#    linenos = BooleanField(required=False)
#    language = ChoiceField(choices=[('Clipper', 'FoxPro'), ('Cucumber', 'Gherkin'), ('RobotFramework', 'RobotFramework'), ('abap', 'ABAP'), ('ada', 'Ada')...
#    style = ChoiceField(choices=[('autumn', 'autumn'), ('borland', 'borland'), ('bw', 'bw'), ('colorful', 'colorful')...

ModelSerializerクラスは特別な処理をしていません.彼はSerializerクラスの簡略化にすぎません.
  • An automatically determined set of fields.
  • Simple default implementations for the create() and update() methods.

  • Writing regular Django views using our Serializer我々が定義したシーケンス可能なオブジェクトを使用して通常のdjango Viewを記述


    次の例ではrest-frameworkの特性を用いずdjangoの方法でviewを確立する
    HttpResponseのサブクラスを作成し、data-』jsonをsnippets/views.py :
    from django.http import HttpResponse
    from django.views.decorators.csrf import csrf_exempt
    from rest_framework.renderers import JSONRenderer
    from rest_framework.parsers import JSONParser
    from snippets.models import Snippet
    from snippets.serializers import SnippetSerializer
    
    class JSONResponse(HttpResponse):
        """
        An HttpResponse that renders its content into JSON.
        """
        def __init__(self, data, **kwargs):
            content = JSONRenderer().render(data)
            kwargs['content_type'] = 'application/json'
            super(JSONResponse, self).__init__(content, **kwargs)
    

    api:既存のsnippetsを取得するか、新しいsnippetsを作成する
    @csrf_exempt
    def snippet_list(request):
        """
        List all code snippets, or create a new snippet.
        """
        if request.method == 'GET':
            snippets = Snippet.objects.all()
            serializer = SnippetSerializer(snippets, many=True)
            return JSONResponse(serializer.data)
    
        elif request.method == 'POST':
            data = JSONParser().parse(request)
            serializer = SnippetSerializer(data=data)
            if serializer.is_valid():
                serializer.save()
                return JSONResponse(serializer.data, status=201)
            return JSONResponse(serializer.errors, status=400)
    
    csrf_exemptは、POSTがCSRF tokenを必要としないことを示しています.通常、rest-frameworkでは、これに対してより良い解決策があります.ここでは簡単な例にすぎません.
    api:retrieve,update or delete用の独立したsnippetsを取得
    @csrf_exempt
    def snippet_detail(request, pk):
        """
        Retrieve, update or delete a code snippet.
        """
        try:
            snippet = Snippet.objects.get(pk=pk)
        except Snippet.DoesNotExist:
            return HttpResponse(status=404)
    
        if request.method == 'GET':
            serializer = SnippetSerializer(snippet)
            return JSONResponse(serializer.data)
    
        elif request.method == 'PUT':
            data = JSONParser().parse(request)
            serializer = SnippetSerializer(snippet, data=data)
            if serializer.is_valid():
                serializer.save()
                return JSONResponse(serializer.data)
            return JSONResponse(serializer.errors, status=400)
    
        elif request.method == 'DELETE':
            snippet.delete()
            return HttpResponse(status=204)
    

    上のview snippets/urls.py:(wire these views up)を宣言します.
    from django.conf.urls import url
    from snippets import views
    
    urlpatterns = [
        url(r'^snippets/$', views.snippet_list),
        url(r'^snippets/(?P[0-9]+)/$', views.snippet_detail),
    ]
    

    url(wire up the root urlconf)tutorial/urls.pyを宣言します.
    from django.conf.urls import url, include
    
    urlpatterns = [
        url(r'^', include('snippets.urls')),
    ]
    

    Tutorial 2:Requests and Responsesリクエストと返信


    Request objects


    rest-frameworkは、HttpRequestから継承されたRequestオブジェクトを採用し、より柔軟なリクエスト解析を提供します.
    コアは属性:request.data
    request.POST  # Only handles form data.  Only works for 'POST' method.
    request.data # Handles arbitrary data.  Works for 'POST', 'PUT' and 'PATCH' methods.
    

    Response objects

    return Response(data)  # Renders to content type as requested by the client.
    

    Status codes

    status moduleは、要求codeを提供します.例えば、HTTP_400_BAD_REQUEST
    デジタルコードを直接使うよりも分かりやすい

    Wrapping API viewsパッケージAPIビュー


    2種類の包装方式:
  • @api_view修飾方法ビュー
  • APIViewパッケージクラスをビューとするapi
  • 包装はいくつかの新しい特性を提供しています.例えば、
  • ビューがRequestインスタンスを受信したことを確認し、Responseを変更します.
  • は405 Method Not Allowed
  • を返します.
  • ParseError
  • をキャプチャ

    Pulling it all together上記rest-frameworkのプロパティライターを使用


    修正snippets/views.py:1.JSOnResponse 2を除去する.viewの変更
    from rest_framework import status
    from rest_framework.decorators import api_view
    from rest_framework.response import Response
    from snippets.models import Snippet
    from snippets.serializers import SnippetSerializer
    
    
    @api_view(['GET', 'POST'])
    def snippet_list(request):
        """
        List all snippets, or create a new snippet.
        """
        if request.method == 'GET':
            snippets = Snippet.objects.all()
            serializer = SnippetSerializer(snippets, many=True)
            return Response(serializer.data)
    
        elif request.method == 'POST':
            serializer = SnippetSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data, status=status.HTTP_201_CREATED)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    @api_view(['GET', 'PUT', 'DELETE'])
    def snippet_detail(request, pk):
        """
        Retrieve, update or delete a snippet instance.
        """
        try:
            snippet = Snippet.objects.get(pk=pk)
        except Snippet.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
    
        if request.method == 'GET':
            serializer = SnippetSerializer(snippet)
            return Response(serializer.data)
    
        elif request.method == 'PUT':
            serializer = SnippetSerializer(snippet, data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
        elif request.method == 'DELETE':
            snippet.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
    

    メリット:
  • コードより簡潔
  • HTTP_を使用400_BAD_400
  • ではなくREQUEST

    Adding optional format suffixes to our URLs urlに接尾辞を追加


    viewの変更view:formatパラメータの追加formatパラメータの追加
    def snippet_list(request, format=None):
    def snippet_detail(request, pk, format=None):
    

    修正urls.py
    urlpatterns = format_suffix_patterns(urlpatterns)
    

    要求を開始して、異なるデータフォーマットに戻ります.
  • セット要求ヘッダ
     Accept:application/json  # Request JSON
     Accept:text/html         # Request HTML
    
  • url接尾辞
     http http://127.0.0.1:8000/snippets.json  # JSON suffix
     http http://127.0.0.1:8000/snippets.api   # Browsable API suffix
    
  • を使用

    Tutorial 3:Class-based Viewクラスビュー


    Rewriting our API using class-based views書き換えview

    views.py :
    from snippets.models import Snippet
    from snippets.serializers import SnippetSerializer
    from django.http import Http404
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import status
    
    
    class SnippetList(APIView):
        """
        List all snippets, or create a new snippet.
        """
        def get(self, request, format=None):
            snippets = Snippet.objects.all()
            serializer = SnippetSerializer(snippets, many=True)
            return Response(serializer.data)
    
        def post(self, request, format=None):
            serializer = SnippetSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data, status=status.HTTP_201_CREATED)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    
    class SnippetDetail(APIView):
        """
        Retrieve, update or delete a snippet instance.
        """
        def get_object(self, pk):
            try:
                return Snippet.objects.get(pk=pk)
            except Snippet.DoesNotExist:
                raise Http404
    
        def get(self, request, pk, format=None):
            snippet = self.get_object(pk)
            serializer = SnippetSerializer(snippet)
            return Response(serializer.data)
    
        def put(self, request, pk, format=None):
            snippet = self.get_object(pk)
            serializer = SnippetSerializer(snippet, data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
        def delete(self, request, pk, format=None):
            snippet = self.get_object(pk)
            snippet.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
    

    修正urls.py:
    from django.conf.urls import url
    from rest_framework.urlpatterns import format_suffix_patterns
    from snippets import views
    
    urlpatterns = [
        url(r'^snippets/$', views.SnippetList.as_view()),
        url(r'^snippets/(?P[0-9]+)/$', views.SnippetDetail.as_view()),
    ]
    
    urlpatterns = format_suffix_patterns(urlpatterns)
    

    Using mixins


    クラスビューを使用するメリット:
  • 多重化可能
  • create/retrieve/update/delete操作rest-frameworkには対応するパッケージクラス
  • があります.
    修正views.py:
    from snippets.models import Snippet
    from snippets.serializers import SnippetSerializer
    from rest_framework import mixins
    from rest_framework import generics
    
    class SnippetList(mixins.ListModelMixin,
                      mixins.CreateModelMixin,
                      generics.GenericAPIView):
        queryset = Snippet.objects.all()
        serializer_class = SnippetSerializer
    
        def get(self, request, *args, **kwargs):
            return self.list(request, *args, **kwargs)
    
        def post(self, request, *args, **kwargs):
            return self.create(request, *args, **kwargs)
    
    class SnippetDetail(mixins.RetrieveModelMixin,
                        mixins.UpdateModelMixin,
                        mixins.DestroyModelMixin,
                        generics.GenericAPIView):
        queryset = Snippet.objects.all()
        serializer_class = SnippetSerializer
    
        def get(self, request, *args, **kwargs):
            return self.retrieve(request, *args, **kwargs)
    
        def put(self, request, *args, **kwargs):
            return self.update(request, *args, **kwargs)
    
        def delete(self, request, *args, **kwargs):
            return self.destroy(request, *args, **kwargs)
    

    基本クラスが追加されました:General APIView
    mixinsメソッド拡張クラス:ListModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin

    Using generic class-based views generic基本クラスの使用


    mixinクラスを使用すると多くのコードを簡略化できますが、mixin機能を含むgenericクラスをより簡潔に使用できます.
    修正views.py:
    from snippets.models import Snippet
    from snippets.serializers import SnippetSerializer
    from rest_framework import generics
    
    
    class SnippetList(generics.ListCreateAPIView):
        queryset = Snippet.objects.all()
        serializer_class = SnippetSerializer
    
    
    class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
        queryset = Snippet.objects.all()
        serializer_class = SnippetSerializer
    

    Tutorial 4:Authentication&Permissions認証と権限


    目的:
  • Code snippets are always associated with a creator.
  • Only authenticated users may create snippets.
  • Only the creator of a snippet may update or delete it.
  • Unauthenticated requests should have full read-only access.

  • Adding information to our model修正model


    変更Snippet/models.py:2つの属性を追加
    owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
    highlighted = models.TextField()
    

    保存方法を追加:
    from pygments.lexers import get_lexer_by_name
    from pygments.formatters.html import HtmlFormatter
    from pygments import highlight
    
    def save(self, *args, **kwargs):
        """
        Use the `pygments` library to create a highlighted HTML
        representation of the code snippet.
        """
        lexer = get_lexer_by_name(self.language)
        linenos = self.linenos and 'table' or False
        options = self.title and {'title': self.title} or {}
        formatter = HtmlFormatter(style=self.style, linenos=linenos,
                                  full=True, **options)
        self.highlighted = highlight(self.code, lexer, formatter)
        super(Snippet, self).save(*args, **kwargs)
    

    データの変更後にデータベースを更新する:ここで更新は古いデータベースを直接削除し、新しいデータベースを作成します.
    rm -f tmp.db db.sqlite3
    rm -r snippets/migrations
    python manage.py makemigrations snippets
    python manage.py migrate
    

    ユーザーの作成:
    python manage.py createsuperuser
    

    Adding endpoints for our User modelsユーザー制御エントリの追加

    serializers.py:Userシーケンサの追加
    from django.contrib.auth.models import User
    
    class UserSerializer(serializers.ModelSerializer):
        snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())
    
        class Meta:
            model = User
            fields = ('id', 'username', 'snippets')
    

    User対応のViewを追加し、views.pyを変更します.
    from django.contrib.auth.models import User
    from snippets.serializers import UserSerializer
    
    
    class UserList(generics.ListAPIView):
        queryset = User.objects.all()
        serializer_class = UserSerializer
    
    
    class UserDetail(generics.RetrieveAPIView):
        queryset = User.objects.all()
        serializer_class = UserSerializer
    

    url urls.pyを追加します.
    url(r'^users/$', views.UserList.as_view()),
    url(r'^users/(?P[0-9]+)/$', views.UserDetail.as_view()),
    

    Associating Snippets with Users関連Snippetsとusers

    views.pyの中のSnippetList類を修正します:次の方法を書き直して、
    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)
    

    Updating our serializer更新シーケンサ


    上のコードはSnippetsと作成したuserを関連付け、次にシーケンス化器を変更します:fieldを追加
    owner = serializers.ReadOnlyField(source='owner.username')
    

    Adding required permissions to views viewsリクエスト権限をviewsに追加


    rest-frameworkにはviewsを要求できるユーザーを制限する権限クラスがたくさんあります.次にIsAuthenticatedOrReadOnlyのみで権限を設定します.views.pyにSnippetList,SnippetDetailクラス属性を追加
    from rest_framework import permissions
    
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
    

    Adding login to the Browsable API追加遊覧機ログインapi

    urls.pyを変更してログインビューurlを追加します.
    urlpatterns += [
        url(r'^api-auth/', include('rest_framework.urls',
                                   namespace='rest_framework')),
    ]
    

    Objectレベルpermissionsオブジェクトレベルの権限


    次のパーミッションを設定します.Snippetsを作成したユーザーは、このSnippetsを変更できます.
    作成snippets/permissions.py:カスタム権限クラスの追加
    from rest_framework import permissions
    
    
    class IsOwnerOrReadOnly(permissions.BasePermission):
        """
        Custom permission to only allow owners of an object to edit it.
        """
    
        def has_object_permission(self, request, view, obj):
            # Read permissions are allowed to any request,
            # so we'll always allow GET, HEAD or OPTIONS requests.
            if request.method in permissions.SAFE_METHODS:
                return True
    
            # Write permissions are only allowed to the owner of the snippet.
            return obj.owner == request.user
    

    SnippetDetailにviews.pyのアクセス権を追加します.
    from snippets.permissions import IsOwnerOrReadOnly
    
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly,)
    

    Now, if you open a browser again, you find that the 'DELETE' and 'PUT' actions only appear on a snippet instance endpoint if you're logged in as the same user that created the code snippet.

    Authenticating with the API認証api


    現在の場所ではauthentication classesは設定されていません.権限に関連するクラスです.そのため、現在のエンジニアリングのデフォルト認証クラスは、SessionAuthentication、BasicAuthenticationです.
    要求時にBasic Authを設定できます:ユーザー名:パスワードアクセスapi

    Tutorial 5:Relationships&Hyperlinked APIs関係とハイパーリンクAPIs


    Creating an endpoint for the root of our APIインタフェースのエントリを作成


    次のコードを追加します:snippets/views.py
    from rest_framework.decorators import api_view
    from rest_framework.response import Response
    from rest_framework.reverse import reverse
    
    
    @api_view(['GET'])
    def api_root(request, format=None):
        return Response({
            'users': reverse('user-list', request=request, format=format),
            'snippets': reverse('snippet-list', request=request, format=format)
        })
    

    上のコード
  • rest-frameworkが提供するreverse法を用いてurl
  • を変換する
  • その対応するURLテンプレートは、後のコードでsnippets/urls.py
  • が表示されます.

    Creating an endpoint for the highlighted snippets

    snippets/views.pyを追加:
    from rest_framework import renderers
    from rest_framework.response import Response
    
    class SnippetHighlight(generics.GenericAPIView):
        queryset = Snippet.objects.all()
        renderer_classes = (renderers.StaticHTMLRenderer,)
    
        def get(self, request, *args, **kwargs):
            snippet = self.get_object()
            return Response(snippet.highlighted)
    
    snippets/urls.pyを追加:
    url(r'^$', views.api_root),
    url(r'^snippets/(?P[0-9]+)/highlight/$', views.SnippetHighlight.as_view()),
    

    Hyperlinking our API apiへのハイパーリンクの作成


    エンティティ・クラス間の関係を処理するには、次のような方法があります.
  • プライマリ・キー
  • を使用
  • Using hyperlinking between entities. ハイパーリンク
  • の使用
  • Using a unique identifying slug field on the related entity.
  • Using the default string representation of the related entity.
  • Nesting the related entity inside the parent representation.
  • Some other custom representation.

  • 次はハイパーリンクで処理します.
    シーケンサの変更HyperlinkedModelSerializerの継承
    HyperlinkedModelSerializerとModelSerializerの違い:
  • It does not include the id field by default. デフォルトではid
  • は含まれません
  • It includes a url field, using HyperlinkedIdentityField. urlプロパティ
  • が含まれています
  • Relationships use HyperlinkedRelatedField, instead of PrimaryKeyRelatedField. リレーショナル・メンテナンスHyperlinkedRelatedField
  • を使用
    修正snippets/serializers.py:
    class SnippetSerializer(serializers.HyperlinkedModelSerializer):
        owner = serializers.ReadOnlyField(source='owner.username')
        highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')
    
        class Meta:
            model = Snippet
            fields = ('url', 'id', 'highlight', 'owner',
                      'title', 'code', 'linenos', 'language', 'style')
    
    
    class UserSerializer(serializers.HyperlinkedModelSerializer):
        snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True)
    
        class Meta:
            model = User
            fields = ('url', 'id', 'username', 'snippets')
    

    Making sure our URL patterns are named urlにパラメータnameが定義されていることを確認

    snippets/urls.py :
    from django.conf.urls import url, include
    from rest_framework.urlpatterns import format_suffix_patterns
    from snippets import views
    
    # API endpoints
    urlpatterns = format_suffix_patterns([
        url(r'^$', views.api_root),
        url(r'^snippets/$',
            views.SnippetList.as_view(),
            name='snippet-list'),
        url(r'^snippets/(?P[0-9]+)/$',
            views.SnippetDetail.as_view(),
            name='snippet-detail'),
        url(r'^snippets/(?P[0-9]+)/highlight/$',
            views.SnippetHighlight.as_view(),
            name='snippet-highlight'),
        url(r'^users/$',
            views.UserList.as_view(),
            name='user-list'),
        url(r'^users/(?P[0-9]+)/$',
            views.UserDetail.as_view(),
            name='user-detail')
    ])
    
    # Login and logout views for the browsable API
    urlpatterns += [
        url(r'^api-auth/', include('rest_framework.urls',
                                   namespace='rest_framework')),
    ]
    

    Adding pagination追加ページング

    tutorial/settings.py :
    REST_FRAMEWORK = {
        'PAGE_SIZE': 10
    }
    

    Tutorial 6: ViewSets & Routers