django-rest-framework学习之路-6-关系和超链接API


django-rest-framework学习之路-6-关系和超链接API

1、创建根路由

我们的项目没有一个根路由,现在我们来创建一个根路由,使用之前介绍的@api_view装饰器

在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)
    })

snippets/views.py变成了

from django.contrib.auth.models import User
from rest_framework import generics, permissions
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse

from snippets.models import Snippet
from snippets.permissions import IsOwnerOrReadOnly
from snippets.serializers import SnippetSerializer, UserSerializer


@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)
    })


class SnippetList(generics.ListCreateAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly, ]

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)


class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer


class UserList(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer


class UserDetail(generics.RetrieveAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

在snippets/urls.py注册路由

path(r'', views.api_root),

并且我们需要改动一下之前的snippets_list路由,给它添加一个路由别名,叫snippet-lis

给users也添加一个路由别名,叫user-list

同时也取出detail的路由别名user-detail和snippet-detail

所以snippets/urls.py变成了

from django.urls import re_path, path
from rest_framework.urlpatterns import format_suffix_patterns

from snippets import views

urlpatterns = [
    re_path(r'^snippets_list/$', views.SnippetList.as_view(), name='snippet-list'),
    re_path(r'^snippets_detail/(?P[0-9]+)/$', views.SnippetDetail.as_view(),name='snippet-detail'),
    re_path(r'^users/$', views.UserList.as_view(), name='user-list'),
    re_path(r'^users/(?P[0-9]+)/$', views.UserDetail.as_view(),name='user-detail'),
    path('', views.api_root),
]

urlpatterns = format_suffix_patterns(urlpatterns)

我们需要定义一个接口,只用于返回高亮的代码

我们只需要把代码中需要高亮的代码返回,然后进行渲染即可,因为我们返回的是Snippet实例的一个属性,也就是highlighted属性,我们不用自动生成其他的方式,比如post、put、delete,我们只需要生成一个get接口,获取到实例的highlighted字段即可,所以我们继承基础类GenericAPIView类

我们还需要使用html渲染,使用使用StaticHTMLRenderer模板进行渲染

然后我们重写get方法

在snippets/views.py中添加

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注册路由

re_path(r'^snippets_list/(?P[0-9]+)/highlight/$', views.SnippetHighlight.as_view(), name='highlight'),

最终snippets/urls.py

from django.urls import re_path, path
from rest_framework.urlpatterns import format_suffix_patterns

from snippets import views

urlpatterns = [
    re_path(r'^snippets_list/$', views.SnippetList.as_view(), name='snippet-list'),
    re_path(r'^snippets_detail/(?P[0-9]+)/$', views.SnippetDetail.as_view(),name='snippet-detail'),
    re_path(r'^users/$', views.UserList.as_view(), name='user-list'),
    re_path(r'^users/(?P[0-9]+)/$', views.UserDetail.as_view(),name='user-detail'),
    re_path(r'^snippets_list/(?P[0-9]+)/highlight/$', views.SnippetHighlight.as_view(), name='snippet-highlight'),
    path('', views.api_root),
]

urlpatterns = format_suffix_patterns(urlpatterns)

使用HyperlinkedModelSerializer来添加超链接

我们想要使用超链接的形式来显示外键关系

或者我们想要自己添加超链接视图,例如我们的highlighted超链接

我们把ModelSerializer变成HyperlinkedModelSerializer

通过HyperlinkedIdentityField关联超链接字段

HyperlinkedModelSerializer与ModelSerializer有以下区别:

  • 默认情况下不包括id字段。
  • 它包含一个url字段,使用HyperlinkedIdentityField。
  • 关联关系使用HyperlinkedRelatedField,而不是PrimaryKeyRelatedField。

snippets/serializers.py变成了:

from django.contrib.auth.models import User
from rest_framework import serializers

from snippets.models import Snippet


# class SnippetSerializer(serializers.ModelSerializer):
#     owner = serializers.ReadOnlyField(source='owner.username')
#
#     class Meta:
#         model = Snippet
#         fields = ('id', 'owner', 'title', 'code', 'linenos', 'language', 'style')
#
#
# class UserSerializer(serializers.ModelSerializer):
#     snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())
#
#     class Meta:
#         model = User
#         fields = ('id', 'username', 'snippets')

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')

highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')表示这是一个超链接,超链接到snippet-highlight,格式是html

确保我们的URL都存在

在上面,我们定义了几个链接,我们要把它都申明出来,他们是:

user-list snippet-list snippet-highlight snippet-detail

来自于这些地方

所以我们的snippets/urls.py文件应该如下所示:

from django.urls import re_path, path
from rest_framework.urlpatterns import format_suffix_patterns

from snippets import views

urlpatterns = [
    re_path(r'^snippets_list/$', views.SnippetList.as_view(), name='snippet-list'),
    re_path(r'^snippets_detail/(?P[0-9]+)/$', views.SnippetDetail.as_view(), name='snippet-detail'),
    re_path(r'^users/$', views.UserList.as_view(), name='user-list'),
    re_path(r'^users/(?P[0-9]+)/$', views.UserDetail.as_view(), name='user-detail'),
    re_path(r'^snippets_list/(?P[0-9]+)/highlight/$', views.SnippetHighlight.as_view(), name='snippet-highlight'),
    path('', views.api_root),
]

urlpatterns = format_suffix_patterns(urlpatterns)

添加分页

我们可以进行分页,不然显示在一页就太长了

修改tutorial/settings.py添加以下设置:

REST_FRAMEWORK = {
    'PAGE_SIZE': 10
}

如果需要的话,我们也可以自定义分页风格,但在这个例子中,我们将一直使用默认设置。

浏览器查看

snippets 根路径 http://127.0.0.1:8000/snippets/

详情 http://127.0.0.1:8000/snippets/snippets_detail/3/

高亮 http://127.0.0.1:8000/snippets/snippets_list/3/highlight/

学习链接 : https://www.w3cschool.cn/lxraw/lxraw-eph335of.html