猿创征文 | DjangoRESTframework(七)-五个扩展类的使用(Create、ListModel,Retrieve,Update,Destroy)

发布于:2022-12-23 ⋅ 阅读:(276) ⋅ 点赞:(0)

Django REST framework(六)-视图之APIVIEW基本视图类,GenericAPIView通用视图类

五个视图扩展类:

rest_framework.mixins.*

作用:

1、提供了增删改查几种后端视图逻辑代码处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。

2、这五个扩展类需要搭配GenericAPIView通用视图基类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。

下面代码用到的序列化器 

from rest_framework.serializers import ModelSerializer
from rest_framework import serializers
from book.models import BookInfo


class BookSerializer(ModelSerializer):
    commentcount = serializers.IntegerField(max_value=10000, min_value=0, default=0)
    readcount = serializers.IntegerField(max_value=10000, min_value=0, default=0)

    class Meta:
        model = BookInfo
        fields = '__all__'
        extra_kwargs = {
            'is_delete': {
                "write_only": True,
                "read_only": False
            },
            'id': {
                "write_only": True,
                "read_only": False,
                "required": False
            }
        }

下面代码所用到的模型类 

# 准备书籍列表信息的模型类
class BookInfo(models.Model):
    # 创建字段,字段类型...
    name = models.CharField(max_length=20, verbose_name='名称')
    pub_date = models.DateField(verbose_name='发布日期', null=True)
    readcount = models.IntegerField(default=0, verbose_name='阅读量')
    commentcount = models.IntegerField(default=0, verbose_name='评论量')
    is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')

    class Meta:
        db_table = 'bookinfo'  # 指明数据库表名
        verbose_name = '图书'  # 在admin站点中显示的名称

    def __str__(self):
        """定义每个数据对象的显示信息"""
        return self.name

数据库数据 

insert into bookinfo(name, pub_date, readcount,commentcount, is_delete) values
('射雕英雄传', '1980-5-1', 12, 34, 0),
('天龙八部', '1986-7-24', 36, 40, 0),
('笑傲江湖', '1995-12-24', 20, 80, 0),
('雪山飞狐', '1987-11-11', 58, 24, 0);

一、ListModelMixin

rest_framework.mixins.ListModelMixin

1、源代码

作用:列表视图扩展类,提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码。该Mixin的list方法会对数据进行过滤和分页。

class ListModelMixin:
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        # 过滤、调用GenericAPIView中的get_queryset()、filter_queryset方法获取过滤后的查询的所有数据
        queryset = self.filter_queryset(self.get_queryset())
        # 分页、调用GenericAPIView中的paginate_queryset对查询数据集进行分页
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        # 实例化序列化器
        serializer = self.get_serializer(queryset, many=True)
        # 返回响应
        return Response(serializer.data)

2、案例 

# 视图
class ListApiView(GenericAPIView, ListModelMixin):
    serializer_class = BookSerializer
    queryset = BookInfo.objects

    def get(self, request):
        # 调用ListModelMixin中的list方法
        return self.list(request)
# 路由
path('demo/listview/', ListApiView.as_view())

 

二、CreateModelMixin

rest_framework.mixins.CreateModelMixin

作用:创建视图扩展类,提供create(request, *args, **kwargs)方法快速实现创建资源的视图,成功返回201状态码。如果序列化器对前端发送的数据验证失败,返回400错误。

1、源代码

class CreateModelMixin:
    """
    Create a model instance.
    """
    def create(self, request, *args, **kwargs):
        # 实例化序列化器
        serializer = self.get_serializer(data=request.data)
        # 验证前端数据
        serializer.is_valid(raise_exception=True)
        # 调用save方法新建数据对象
        self.perform_create(serializer)
        # 设置响应头
        headers = self.get_success_headers(serializer.data)
        # 返回响应
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def perform_create(self, serializer):
        serializer.save()

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):

            return {}

2、案例

# 视图
class CreateApiView(GenericAPIView, CreateModelMixin):
    serializer_class = BookSerializer
    queryset = BookInfo.objects

    def post(self, request):
        return self.create(request)
# 路由
path('demo/createview/', CreateApiView.as_view()),

 三、RetrieveModelMixin

rest_framework.mixins.RetrieveModelMixin

 作用: 通过url路径参数查询某个模型对象返回该模型对象的数据,如果存在,返回200, 否则返回404。

1、源代码

class RetrieveModelMixin:
    """
    Retrieve a model instance.
    """
    def retrieve(self, request, *args, **kwargs):
        # 通过url路径参数查询某个模型对象
        instance = self.get_object()
        # 实例化序列化器
        serializer = self.get_serializer(instance)
        # 返回响应
        return Response(serializer.data)

2、案例

# 视图
class RetrieveApiView(GenericAPIView, RetrieveModelMixin):
    serializer_class = BookSerializer
    queryset = BookInfo.objects

    def get(self, request, pk):
        return self.retrieve(request)
# 路由
re_path(r'^demo/retrieveview/(?P<pk>\d+)/$', RetrieveApiView.as_view()),

 

四、UpdateModelMixin

rest_framework.mixins.UpdateModelMixin

作用:更新视图扩展类,提供update(request, *args, **kwargs)方法,可以快速实现更新一个存在的数据对象。同时也提供partial_update(request, *args, **kwargs)方法,可以实现局部更新。成功返回200,序列化器校验数据失败时,返回400错误。

1、源代码

class UpdateModelMixin:
    """
    Update a model instance.
    """
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        # 通过url路径参数查询某个模型对象
        instance = self.get_object()
        # 实例化序列化器
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        # 验证前端数据
        serializer.is_valid(raise_exception=True)
        # 调用save方法更新模型对象的数据
        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(serializer.data)

2、案例

# 视图
class UpdateApiView(GenericAPIView, UpdateModelMixin):
    serializer_class = BookSerializer
    queryset = BookInfo.objects

    def put(self, request, pk):
        return self.update(request)
# 路由
re_path(r'^demo/updateview/(?P<pk>\d+)/$', UpdateApiView.as_view()),

五、DestroyModelMixin

rest_framework.mixins.DestroyModelMixin

作用:删除视图扩展类,提供destroy(request, *args, **kwargs)方法,可以快速实现删除一个存在的数据对象。成功返回204,不存在返回404。

1、源代码


class DestroyModelMixin:
    """
    Destroy a model instance.
    """
    def destroy(self, request, *args, **kwargs):
        # 通过url路径参数查询某个模型对象
        instance = self.get_object()
        # 删除模型对象
        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        instance.delete()

 2、案例

# 视图
class DestroyApiView(GenericAPIView, DestroyModelMixin):
    queryset = BookInfo.objects

    def delete(self, request, pk):
        return self.destroy(request)
# 路由
 re_path(r'^demo/deleteview/(?P<pk>\d+)/$', DestroyApiView.as_view()),

 

六、总结

1、整合代码(相比在之前代码中写的)

现在的

# 视图
class BooksMixinsView(GenericAPIView, ListModelMixin, CreateModelMixin):
    serializer_class = BookSerializer
    queryset = BookInfo.objects

    def get(self, request):
        """获取所有模型对象数据"""
        return self.list(request)

    def post(self, request):
        """创建模型对象数据"""
        return self.create(request)


class BookMixinsView(GenericAPIView, DestroyModelMixin, RetrieveModelMixin, UpdateModelMixin):
    serializer_class = BookSerializer
    queryset = BookInfo.objects

    def get(self, request, pk):
        """获取单一模型对象数据"""
        return self.retrieve(request, pk=pk)

    def delete(self, request, pk):
        """删除单一模型对象数据"""
        return self.destroy(request, pk=pk)

    def put(self, request, pk):
        """修改单一模型对象数据"""
        return self.update(request, pk=pk)

#路由
path('demo/books/', BooksMixinsView.as_view()),
re_path(r'^demo/books/(?P<pk>\d+)/$', BookMixinsView.as_view()),

之前的 (Django REST framework(六)-视图之APIVIEW基本视图类,GenericAPIView通用视图类

class BookGenericAPIView(GenericAPIView):
    queryset = BookInfo.objects
    serializer_class = BookSerializer

    def get(self, request, pk):
        """获取单一图书信息"""
        book = self.get_object()  # 该方法自动获取路径参数pk查询某一模型对象
        ser = self.get_serializer(instance=book)
        data = ser.data
        return Response(data=data, status=status.HTTP_200_OK)

    def put(self, request, pk):
        book = self.get_object()
        ser = self.get_serializer(instance=book, data=request.data)
        if ser.is_valid() is False:
            return Response(data=ser.errors, status=status.HTTP_424_FAILED_DEPENDENCY)
        ser.save()
        data = ser.data
        return Response(data=data, status=status.HTTP_200_OK)

    def delete(self, request, pk):
        self.get_object().delete()
        return Response('删除成功', status=status.HTTP_200_OK)


class BooksGenericAPIView(GenericAPIView):
    # 多个序列化器的情况
    # def get_serializer_class(self):
    #     if self.request.method.lower() == "put":
    #         return Serializer1
    #     else:
    #         return Serializer2
    # 单个序列化器的情况
    serializer_class = BookSerializer
    queryset = BookInfo.objects

    def get(self, request):
        """返回所有图书信息"""
        books = self.get_queryset()
        ser = self.get_serializer(instance=books, many=True)
        data = ser.data
        return Response(data=data, status=status.HTTP_200_OK)

    def post(self, request):
        """增加一个新的图书信息"""
        ser = self.get_serializer(data=request.data)
        if ser.is_valid() is False:
            return Response(data=ser.errors)
        ser.save()
        data = ser.data
        return Response(data=data, status=status.HTTP_200_OK)

测试 

 2、总结

相比于GenericAPIView:

  • 五个扩展类基于GenericAPIView的基础上实现代码的封装
  • 五个扩展类只是对于增删改查进行了代码封装,并未实现as_view()等View的相关的方法,所以不能单独用于视图,需要和GenericAPIView相互配合使用
  • 五个扩展类视图只需要在继承之后定义查询集对象序列化器后,再调用相应的方法即可使用。

网站公告

今日签到

点亮在社区的每一天
去签到