response下的Response的二次封装和视图家族

自己总结

继承APIView流程

APIView类
as_view(): 就干了一件事:禁用了csrf中间件的安全认证
dispatch():

  1. 二次封装request对象,将原wsgi的request对象保留至 _request 中
  2. 将数据包中的数据解析到request.data,将url链接?后的数据解析到request.query_params
  3. drf的三大认证
  4. 二次处理响应对象response在返回

封装Response

from rest_framework.response import Response
class APIResponse(Response):
    def __init__(self, data_status, msg, results=None, headers=None, status=None, **kwargs):
        data = {
            'status': data_status,
            'msg': msg,
        }
        if results:
            data['results'] = results
        data.update(kwargs)
        super().__init__(data=data, headers=headers, status=status)

使用:APIResponse(0, 'ok', {}, headers, status)

允许局部修改

partial=Ture
context可以完成视图类给序列化类传参,需要在视图里面写,在序列化类中通过钩子函数中的validate_名字中的self.context.get('名字来捕获')

局部钩子

全局钩子

设置群体资源校验类ListSerializer

1、在序列化中
class Meta:
# 设置群体资源校验类
list_serializer_class = BooksListSerializer
2、在群体资源类中
class BooksListSerializer(serializers.ListSerializer):
# ListSerializer已提供create的实现体,有特殊需求可以重写
def create(self, validated_data):
# print('>>>', validated_data)
return super().create(validated_data)

# ListSerializer未提供update的实现体,必须重写
def update(self, instance, validated_data):
    # print('***', instance, validated_data)
    for index, book_obj in enumerate(instance):
        book_dic = validated_data[index]  # type: dict
        for k, v in book_dic.items():
            if hasattr(book_obj, k):
                setattr(book_obj, k, v)
        # 同步到数据库
        book_obj.save()
    # print("+++", instance)
    return instance

GenericeAPIView视图

from rest_framework.generics import GenericAPIView
继承:GenericAPIView
1、需要提供queryset和serializer类属性
queryset = models.Book.objects.filter(is_delete=False)
serializer_class = serializers.BooksModelSerializer
2、在请求方法中通过self.get_queryset和self.get_serializerl来获取

主要作用是简化了queryset和serializer_class,将这两个变量提取到了类属性中,但是get、post、put、等方法还是得自己写

mixins视图工具类

封装了增删改查5大接口
from rest_framework import mixins
继承:mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericAPIView
CreateModelMixin单增 DestoryModelMixin单删,listModelMIxin群查,RetrieveModelMixin单查,UpdateModelMixin单更
1、需要提供queryset和serializer类属性
queryset = models.Book.objects.filter(is_delete=False)
serializer_class = serializers.BooksModelSerializer
2、方法都被封装好了,使用只需要调用和继承相应的方法即可,两行

整合mixins 到 generics 中(ListCreateAPIView)

不需要自己写功能,只需要提供queryset和serializer类属性即可,单需要继承相应的方法

viewsets:视图集(重要)

整合了mixins和viewsets.GenericViewSet
rom rest_framework import viewsets
继承:mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet
1、ViewSetMixin重写了as_view方法,路由层掉用as_view方法就是掉用此方法
2、能够实现5大接口并且自定义5大接口,即能够实现10大接口
3、路由层需要传参,传入不同的请求对应部同的方法,来实现分发

4、通过路由插拔式的方法来根据需求,需要自己写的自己来写方法,不需要的就用系统的方法

老师笔记

ListSerializer类:群增 群改

数据层:还是采用Book、Publish、Author、AuthorDetail四个Model类

序列化层:

from rest_framework import serializers
from . import models

# 利用 ListSerializer 类完成群增群改
class BooksListSerializer(serializers.ListSerializer):
    # ListSerializer已提供create的实现体,有特殊需求可以重写
    def create(self, validated_data):
        # print('>>>', validated_data)
        return super().create(validated_data)

    # ListSerializer未提供update的实现体,必须重写
    def update(self, instance, validated_data):
        # print('***', instance, validated_data)
        for index, book_obj in enumerate(instance):
            book_dic = validated_data[index]  # type: dict
            for k, v in book_dic.items():
                if hasattr(book_obj, k):
                    setattr(book_obj, k, v)
            # 同步到数据库
            book_obj.save()
        # print("+++", instance)
        return instance

class BooksModelSerializer(serializers.ModelSerializer):
    class Meta:
        # 设置群体资源校验类
        list_serializer_class = BooksListSerializer

        # 关联的Model类
        model = models.Book
        fields = ('name', 'price', 'publish', 'authors')
        extra_kwargs = {
            'publish': {
                'write_only': True
            },
            'authors': {
                'write_only': True
            },
            'price': {
                # 数据库字段设置了默认值,也需要 反序列化 时必须提供该字段
                'required': True,
                'error_messages': {
                    'required': '价格不能为空',
                }
            },
            'name': {
                'min_length': 3,
                'error_messages': {
                    'min_length': '太短',
                }
            },
        }

    def validate_name(self, value: str):
        # 拿视图类传递过来的参数
        # print(self.context.get('owner'))
        if not value.isidentifier():
            raise serializers.ValidationError('名字非法')
        return value

    def validate(self, attrs):
        # 同一出版社书面相同,代表书是同一本,不存入数据库
        name = attrs.get('name')
        publish = attrs.get('publish')
        # print(name, type(name))
        # print(publish, type(publish))
        if models.Book.objects.filter(name=name, publish=publish):
            raise serializers.ValidationError({'%s' % name: '已存在'})
        return attrs

视图层

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from . import models, serializers
from utils.response import APIResponse
class BooksAPIView(APIView):
    # 获取所有 | 一个
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            books_query = models.Book.objects.filter(is_delete=False, pk=pk)
        else:
            books_query = models.Book.objects.filter(is_delete=False).order_by('id')
        books_data = serializers.BooksModelSerializer(books_query, many=True).data
        return APIResponse(0, 'ok', books_data)

    # 新增多个 | 一个
    def post(self, request, *args, **kwargs):
        request_data = request.data
        # if isinstance(request_data, list): # 群增
        #     many = True
        # else: # 单增
        #     many = False
        many = True if isinstance(request_data, list) else False
        book_ser = serializers.BooksModelSerializer(data=request_data, many=many)
        if book_ser.is_valid():
            book_obj_list = book_ser.save()
            return APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj_list, many=many).data)
        else:
            return APIResponse(1, 'failed', book_ser.errors)

    # 修改一个
    def put(self, request, *args, **kwargs):
        pk = kwargs.get('pk', 1)
        book_obj = models.Book.objects.filter(pk=pk, is_delete=False).first()
        book_ser = serializers.BooksModelSerializer(instance=book_obj, data=request.data)
        if book_ser.is_valid():
            book_obj = book_ser.save()
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': serializers.BooksModelSerializer(book_obj).data
            })
        else:
            return Response({
                'status': 1,
                'msg': 'failed',
                'results': book_ser.errors
            })

    # 局部修改多个 | 一个
    """
    def patch(self, request, *args, **kwargs):
        request_data = request.data
        many = True if isinstance(request_data, list) else False
        if many:  # 群改
            pks = [book_dic.pop('pk') for book_dic in request_data]
            # print(pks, request_data)
            book_query = models.Book.objects.filter(pk__in=pks, is_delete=False)
            book_ser = serializers.BooksModelSerializer(partial=True, many=True, instance=book_query, data=request_data)
            if book_ser.is_valid():
                book_obj_list = book_ser.save()
                return APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj_list, many=True).data)
            else:
                return APIResponse(1, 'failed', book_ser.errors)
        else:  # 单改
            pk = kwargs.get('pk')
            book_query = models.Book.objects.filter(pk=pk, is_delete=False)
            # partial=True允许操作 局部的反序列化字段
            book_ser = serializers.BooksModelSerializer(partial=True, many=True, instance=book_query, data=[request_data])
            # context可以完成视图类给序列化类传递参数
            # book_ser = serializers.BooksModelSerializer(partial=True,instance=book_obj, data=request.data,context={'owner': 'Owen'})

            if book_ser.is_valid():
                book_obj = book_ser.save()
                return APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj, many=True).data)
            else:
                return APIResponse(1, 'failed', book_ser.errors)
    """

    def patch(self, request, *args, **kwargs):
        request_data = request.data
        # 群改:往 /Books/ 发送 [{"pk":1,"name":"西游记"},{"pk":2,"price":"1.00"}]  pk是必须字段
        if isinstance(request_data, list):
            pks = [book_dic.pop('pk') for book_dic in request_data]
        else:  # 单改:往 /Books/(pk)/ 发送 {"name":"西游记"}
            pks = [kwargs.get('pk')]
            request_data = [request_data]
        book_query = models.Book.objects.filter(pk__in=pks, is_delete=False)
        book_ser = serializers.BooksModelSerializer(partial=True, many=True, instance=book_query, data=request_data)
        if book_ser.is_valid():
            book_obj_list = book_ser.save()
            return APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj_list, many=True).data)
        else:
            return APIResponse(1, 'failed', book_ser.errors)


    # 删除一个 /books/1/ | 删除多个 /books/  数据[1, 2]
    def delete(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            pks = [pk]
        else:
            pks = request.data
        delete_rows = models.Book.objects.filter(pk__in=pks, is_delete=False).update(is_delete=True)
        if delete_rows != 0:
            return APIResponse(0, 'ok')
        return APIResponse(1, '删除失败')

视图家族:

数据层、序列化层:不变

视图层:

"""
generics:视图类
重点:将 queryset对象 与 serializer对象 封装成类属性

mixins:视图工具集
重点:通过list、create、update、destroy、retrieve五大功能(依赖generics类)

viewsets:视图集
重点:通过ViewSetMixin完成请求方法的自定义映射(整合mixins、 generics、ViewSetMixin)
"""
from rest_framework.generics import GenericAPIView
from . import models, serializers
from utils.response import APIResponse

# generics:视图类
class BooksGenericAPIView(GenericAPIView):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BooksModelSerializer
    # lookup_field = 'pk'  # 与urls中的有名分组,有名分组为pk可以省略
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if not pk:
            book_query = self.get_queryset()
            book_ser = self.get_serializer(book_query, many=True)
            return APIResponse(0, 'ok', book_ser.data)
        else:
            book_obj = self.get_object()
            book_ser = self.get_serializer(book_obj)
            return APIResponse(0, 'ok', book_ser.data)


# mixins:视图工具集
from rest_framework import mixins
class BooksMixinsGenericAPIView(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericAPIView):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BooksModelSerializer
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if not pk:
            return self.list(request, *args, **kwargs)
        else:
            return self.retrieve(request, *args, **kwargs)


# 整合mixins 到 generics 中:不需要自己写功能
from rest_framework.generics import ListCreateAPIView, RetrieveAPIView
class BooksListAPIView(ListCreateAPIView):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BooksModelSerializer


# 重点
# viewsets:视图集(整合mixins 到 generics)、
from rest_framework import viewsets
class BooksGenericViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BooksModelSerializer

    def create_many_or_one(self, request, *args, **kwargs):
        request_data = request.data
        many = True if isinstance(request_data, list) else False
        book_ser = serializers.BooksModelSerializer(data=request_data, many=many)
        if book_ser.is_valid():
            book_obj_list = book_ser.save()
            return APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj_list, many=many).data)
        else:
            return APIResponse(1, 'failed', book_ser.errors)

路由层

from django.conf.urls import url, include
from . import views
urlpatterns = [
    url(r'^v1/books/$', views.BooksGenericAPIView.as_view()),
    url(r'^v1/books/(?P<pk>d+)/', views.BooksGenericAPIView.as_view()),
    url(r'^v2/books/$', views.BooksMixinsGenericAPIView.as_view()),
    url(r'^v2/books/(?P<pk>d+)/', views.BooksMixinsGenericAPIView.as_view()),
    url(r'^v3/books/$', views.BooksListAPIView.as_view()),
    url(r'^v3/books/(?P<pk>d+)/', views.BooksListAPIView.as_view()),
    # 重点:
    url(r'^v4/books/$', views.BooksGenericViewSet.as_view({'get': 'list', 'post': 'create_many_or_one'})),
    url(r'^v4/books/(?P<pk>d+)/', views.BooksGenericViewSet.as_view({'get': 'retrieve'})),
]

路由组件:了解

from django.conf.urls import url, include
from . import views

from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('books', views.BooksGenericViewSet, base_name='book')

# url(r'^v1/books/$', views.BooksGenericAPIView.as_view()),
# url(r'^v1/books/(?P<pk>d+)/', views.BooksGenericAPIView.as_view()),
# 第一种方式
urlpatterns = []
urlpatterns.extend(router.urls)

# 第二种方式
urlpatterns = [
    url(r'^', include(router.urls)),
]
原文地址:https://www.cnblogs.com/huanghongzheng/p/11369574.html