DjangoREST视图组件 apiview&viewset
发布日期:2021-05-28 17:08:44 浏览次数:23 分类:技术文章

本文共 11734 字,大约阅读时间需要 39 分钟。

文章目录


一、serializer进行put、delete及获取单条数据的接口设计

1.1. 使用serializer进行put接口设计

urls.py

re_path(r'books/(\d+)/$', views.BookFilterView.as_view())

views.py

from rest_framework.views import APIViewfrom app_serializer import BookSerializerclass BookFilterView(APIView):    def put(self, request, nid):        book_obj = Book.objects.get(pk=nid)        serialized_data = BookSerializer(data=request.data, instance=book_obj)        if serialized_data.is_valid():            serialized_data.save()        else:            return Response(serialized_data.errors)

serializer.py

class BookSerializer(serializers.ModelSerializer):    class Meta:        model = Book        fields = ('title',                  'price',                  'publish',                  'authors',                  'author_list',                  'publish_name',                  'publish_city'                  )        extra_kwargs = {
'publish': {
'write_only': True}, 'authors': {
'write_only': True} } publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name') publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city') author_list = serializers.SerializerMethodField() def get_author_list(self, book_obj): # 拿到queryset开始循环 [{
}, {
}, {
}, {
}] authors = list() for author in book_obj.authors.all(): authors.append(author.name) return authors

除了传入data参数外,还需告诉序列化组件,我们需要更新哪条数据,也就是instance,另外,我们使用的序列化类还是之前那个

class BookSerializer(serializers.ModelSerializer):    class Meta:        model = Book        fields = ('title',                  'price',                  'publish',                  'authors',                  'author_list',                  'publish_name',                  'publish_city'                  )        extra_kwargs = {
'publish': {
'write_only': True}, 'authors': {
'write_only': True} } publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name') publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city') author_list = serializers.SerializerMethodField() def get_author_list(self, book_obj): # 拿到queryset开始循环 [{
}, {
}, {
}, {
}] authors = list() for author in book_obj.authors.all(): authors.append(author.name) return authors

1.2. 使用serializer进行delete接口设计

urls.py

re_path(r'books/(\d+)/$', views.BookFilterView.as_view()),

views.py

class BookFilterView(APIView):    def delete(self, request, nid):        book_obj = Book.objects.get(pk=nid).delete()        return Response("")    def put(self, request, nid):        book_obj = Book.objects.get(pk=nid)        serialized_data = BookSerializer(data=request.data, instance=book_obj)        if serialized_data.is_valid():            serialized_data.save()            return Response(serialized_data.data)        else:            return Response(serialized_data.errors)

1.3 使用serializer进行单条数据的接口设计

urls.py不变,新增三个接口逻辑后的视图类如下

class BookFilterView(APIView):    def get(self, request, nid):        book_obj = Book.objects.get(pk=nid)        serialized_data = BookSerializer(book_obj, many=False)        return Response(serialized_data.data)    def delete(self, request, nid):        book_obj = Book.objects.get(pk=nid).delete()        return Response("")    def put(self, request, nid):        book_obj = Book.objects.get(pk=nid)        serialized_data = BookSerializer(data=request.data, instance=book_obj)        if serialized_data.is_valid():            serialized_data.save()            return Response(serialized_data.data)        else:            return Response(serialized_data.errors)

不传参数时

class BookView(APIView):    def get(self, request):        origin_books = Book.objects.all()        serialized_books = BookSerializer(origin_books, many=True)        return Response(serialized_books.data)    def post(self, request):        verified_data = BookSerializer(data=request.data)        if verified_data.is_valid():            book = verified_data.save()            return Response(verified_data.data)        else:            return Response(verified_data.errors)

二、优化接口逻辑

2.2 使用mixin优化接口逻辑

urls.py有些区别:

from django.urls import re_pathfrom mixiner import viewsurlpatterns = [    re_path(r'books/$', views.BookView.as_view()),    re_path(r'books/(?P
\d+)/$', views.BookFilterView.as_view()),]

views.py

from rest_framework.mixins import (    ListModelMixin,    CreateModelMixin,    UpdateModelMixin,    DestroyModelMixin,    RetrieveModelMixin)from rest_framework.generics import GenericAPIView# 当前app中的模块from .models import Bookfrom mixin_serializer import BookSerializer# Create your views here.class BookView(ListModelMixin, CreateModelMixin, GenericAPIView):    queryset = Book.objects.all()    serializer_class = BookSerializer    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 BookFilterView(DestroyModelMixin,                     UpdateModelMixin,                     RetrieveModelMixin,                     GenericAPIView):    queryset = Book.objects.all()    serializer_class = BookSerializer    def get(self, request, *args, **kwargs):        return self.retrieve(request, *args, **kwargs)    def delete(self, request, *args, **kwargs):        return self.destroy(request, *args, **kwargs)    def put(self, request, *args, **kwargs):        return self.update(request, *args, **kwargs)

mixin源码剖析

1. Django程序启动,开始初始化,读取urls.py, 读取settings, 读取视图类2. 执行as_views(), BookView没有,需要到父类中找3. 几个ModelMixin也没有,GenericAPIView中没有,继续到GenericAPIView(APIView)中找4. 找到了,并且与之前的逻辑是一样的,同时我们发现GenericAPIView中定义了查找queryset和serializer_class类的方法5. as_view()方法返回重新封装的视图函数,开始建立url和视图函数之间的映射关系6. 等待用户请求7. 接收到用户请求,根据url找到视图函数8. 执行视图函数的dispatch方法(因为视图函数的返回值是:return self.dispatch()9. dispatch分发请求,查找到视图类的五个方法中的某个10. 开始执行,比如post请求,返回:self.create(),视图类本身没有,则会到父类中查找11. 最后在CreateModelMixin中查找12. 执行create()方法,获取queryset和serializer_class13. 返回数据

2.2 使用view优化接口逻辑

# -*- coding: utf-8 -*-from rest_framework import generics# 当前app中的模块from .models import Bookfrom .serializer_classes import BookSerializer# Create your views here.class BookView(generics.ListCreateAPIView):    queryset = Book.objects.all()    serializer_class = BookSerializerclass BookFilterView(generics.RetrieveUpdateDestroyAPIView):    queryset = Book.objects.all()    serializer_class = BookSerializer

2.3 使用viewset优化接口逻辑

urls.py有变化:

from django.urls import re_pathfrom viewsetter import viewsurlpatterns = [    re_path(r'books/$', views.BookView.as_view({
'get': 'list', 'post': 'create' })), re_path(r'books/(?P
\d+)/$', views.BookView.as_view({
'get': 'retrieve', 'put': 'update', 'delete': 'destroy' })),]

view.py

# -*- coding: utf-8 -*-# django rest framework组件from rest_framework.viewsets import ModelViewSet# 当前app中的模块from .models import Bookfrom .serializer_classes import BookSerializer# Create your views here.class BookView(ModelViewSet):    queryset = Book.objects.all()    serializer_class = BookSerializer

viewset源码剖析

1. Django程序启动,开始初始化,读取urls.py, 读取settings, 读取视图类2. 执行as_views(), BookView没有,需要到父类(ModelViewSet)中找3. ModelViewSet继承了mixins的几个ModelMixin和GenericViewSet,显然ModelMixin也没有,只有GenericViewSet中有4. GenericViewSet没有任何代码,只继承了ViewSetMixin和generics.GenericAPIView(这个我们已经认识了)5. 继续去ViewSetMixin中查找,找到了as_view类方法,在重新封装view函数的过程中,有一个self.action_map = actions6. 这个actions就是我们给as_view()传递的参数7. 绑定url和视图函数(actions)之间的映射关系8. 等待用户请求9. 接收到用户请求,根据url找到视图函数10. 执行视图函数的dispatch方法(因为视图函数的返回值是:return self.dispatch()11. dispatch分发请求,查找到视图类的五个方法中的某个12. 开始执行,比如post请求,返回:self.create(),视图类本身没有,则会到父类中查找13. 最后在CreateModelMixin中查找14. 执行create()方法,获取queryset和serializer_class15. 返回数据

三 viewset

几种view以及他们之间的关系。

在这里插入图片描述
mixins,主要也分为5类

在这里插入图片描述

1.首先,我们使用django自带的view,获取一个课程的列表

# drf是通过json的格式进行数据交互的,所以这里也返回json数据import jsonfrom django.views.generic.base import Viewfrom django.core import serializersfrom django.http import HttpResponse,JsonResponsefrom .models import Courseclass CourseListView(View):    def get(self, request):        """        通过django的view实现课程列表页        """        courses = Course.objects.all()[:10]        json_data = serializers.serialize('json', Courses)        json_data = json.loads(json_data)        return JsonResponse(json_data, safe=False)

APIView

from rest_framework.views import APIViewfrom rest_framework.response import Response# 这个serializers是在其他文件自定义的from .serializers import CourseSerializerclass CourseListView(APIView):    def get(self, request, format=None):        """        通过APIView实现课程列表页        """        courses = Course.objects.all()        serializer = CourseSerializer(courses, many=True)        return Response(serializer.data)

GenericAPIView

from rest_framework import mixinsfrom rest_framework import genericsclass CourseListView(mixins.ListModelMixin, generics.GenericAPIView):    """    课程列表页    """    queryset = Course.objects.all()    serialize_class = CourseSerializer    def get(self, request, *args, **kwargs):    # list方法是存在于mixins中的,同理,create等等也是    # GenericAPIView没有这些方法!        return self.list(request, *args, **kwargs)

ViewSet功能

GenericViewSet继承了GenericAPIView,依然有get_queryset,get_serialize_class相关属性与方法,GenericViewSet重写了as_view方法,可以获取到HTTP的请求方法

from rest_framework import viewsetsimport...class CourseViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):    queryset = Course.objects.all()        def get_serializer_class(self):    # 重写get_serializer_class方法        if self.action == 'list':            return CourseSerializer        return CourseDetailSerializer

http请求方法与mixins的方法进行绑定 GenericViewSet本身依然不存在list, create方法,需要我们与mixins一起混合使用 重写as_view的方法为我们提供了绑定的功能

# 进行绑定courses = CourseViewSet.as_view({
'get': 'list', 'post': 'create'})urlpatterns = [ ... # 常规加入url匹配项 url(r'courses/', CourseViewSet.as_view(), name='courses')]

简洁的方法route方法注册与绑定

from rest_framework.routers import DefaultRouterrouter = DefaultRouter() # 只需要实现一次router.register(r'courses', CourseViewSet, base_name='courses')urlpatterns = [    ...    # 只需要加入一次    url(r'^', include(router.urls)),]

四. 修改 ModelViewSet 的默认返回信息

drf API 接口默认返回的只是数据的JSON字符串。源码发现这些返回信息是写在create()、list()、retrieve()、update()、destroy()这些方法里的

ModelViewSet直接继承了6个父类:

class ModelViewSet(mixins.CreateModelMixin,                   mixins.RetrieveModelMixin,                   mixins.UpdateModelMixin,                   mixins.DestroyModelMixin,                   mixins.ListModelMixin,                   GenericViewSet):    """    A viewset that provides default `create()`, `retrieve()`, `update()`,    `partial_update()`, `destroy()` and `list()` actions.    """    pass

类里面的对应的方法的return Response就可以了。以update为例:

class MyModelViewSet(viewsets.ModelViewSet):    def update(self, request, *args, **kwargs):        partial = kwargs.pop('partial', False)        instance = self.get_object()        serializer = self.get_serializer(instance, data=request.data, partial=partial)        is_valid = serializer.is_valid(raise_exception=False)        #######        if not is_valid:            return Response({
'code': 0, 'msg': '失败', 'data': serializer.errors}) self.perform_update(serializer) ###### if getattr(instance, '_prefetched_objects_cache', None): # If 'prefetch_related' has been applied to a queryset, we need to # forcibly invalidate the prefetch cache on the instance. instance._prefetched_objects_cache = {
} return Response({
'code': 1, 'msg': '成功', 'data': serializer.data})

或直接修改源码

在这里插入图片描述
测试如下
在这里插入图片描述


转载地址:https://blog.csdn.net/qq_35911309/article/details/113534397 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Django 用户认证 Auth
下一篇:Django JSON序列化器/解析器

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2024年09月24日 18时51分39秒