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

Django REST framwork 提供的视图的主要作用:

- 控制序列化器的执行(检验、保存、转换数据)

- 控制数据库查询的执行

- 调用请求类和响应类

一、APIVIEW基本视图类

rest_framework.views.APIView

APIView是REST framework提供的所有视图类的基类,继承自Django的View父类。

APIViewView的区别在于:

  • REST framework使用rest.framework.request.Request对象,而Django使用django.core.handlers.wsgi.WSGIRequest对象;

  • REST framework的rest.framework.response.Response对象,视图会为响应数据设置(renderer)符合前端期望要求的格式;

  • 任何APIException异常都会被捕获到,并且处理成合适格式的响应信息返回给客户端;

    django 的View中所有异常全部以HTML格式显示,drf的APIVIew或者APIView的子类会自动根据客户端的Accept进行错误信息的格式转换。

  • 重新声明了一个新的as_view方法并在dispatch()进行路由分发前,会对请求的客户端进行身份认证、权限检查、流量控制。

APIView除了继承了View原有的属性方法意外,还新增了类属性:

  • authentication_classes 列表或元组,身份认证类

  • permissoin_classes 列表或元组,权限检查类

  • throttle_classes 列表或元祖,流量控制类

APIView中仍以常规的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。

 

1、定义序列化器

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 #数据库自增,不用传
            }
        }

2、定义视图

from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

from book.models import BookInfo
from demo.Serializer import BookSerializer


class BookApiView(APIView):
    def get(self, request, pk):
        """获取一本本书的信息"""
        book = BookInfo.objects.get(id=pk)
        ser = BookSerializer(instance=book)
        data = ser.data
        return Response(data=data, status=status.HTTP_200_OK)

    def put(self, request, pk):
        """更新一本书的信息"""
        client_book_info = request.data
        book = BookInfo.objects.get(id=pk)
        ser = BookSerializer(instance=book, data=client_book_info)
        if ser.is_valid() is False:
            return Response(ser.errors)
        ser.save()
        data = ser.data
        return Response(data=data, status=status.HTTP_200_OK)

    def delete(self, request, pk):
        """删除一本书的信息"""
        try:
            BookInfo.objects.get(id=pk).delete()
        except BookInfo.DoesNotExist:
            return Response('数据不存在', status=status.HTTP_404_NOT_FOUND)

        return Response('删除成功', status=status.HTTP_200_OK)


class BooksApiView(APIView):
    def get(self, request):
        """获取所有图书的信息"""
        books = BookInfo.objects.all()
        ser = BookSerializer(instance=books, many=True)
        data = ser.data
        return Response(data=data, status=status.HTTP_200_OK)

    def post(self, request):
        """增加一本书"""
        books = request.data
        ser = BookSerializer(data=books)
        if ser.is_valid() is False:
            return Response(ser.errors)
        ser.save()
        data = ser.data
        return Response(data, status.HTTP_200_OK)

3、定义路由

from django.urls import path, re_path

from .views import *

urlpatterns = [

    re_path(r'^demo/books/(?P<pk>\d+)/$', BookApiView.as_view()),
    path('demo/books/', BooksApiView.as_view())

]

4、测试

二、 GenericAPIView通用视图类

rest_framework.generics.GenericAPIView

GenericAPIView通用视图类:

  • 通用视图类主要作用就是把视图中的独特的代码抽取出来,让视图方法中的代码更加通用,方便把通用代码进行简写。
  • APIView中的api接口代码,除了部分涉及到调用模型和序列化器的代码以外,其他代码几乎都是固定写法。
  • 所以,当我们将来针对增删查改的通用api接口编写时,完全可以基于原有的代码进行复用,
  • 那么,drf也考虑到了这个问题,所以提供了一个GenericAPIView(通用视图类),让我们可以把接口中独特的代码单独提取出来作为属性存在。
  • rest_framework.generics.GenericAPIView是APIView的子类,在APIView的基础上进行属性扩展提供了2个属性,4个方法,方便我们针对通用接口进行编写。

GenericAPIView通用视图类的主要作用在于:

  • 提供了操作序列化器(同一个类视图的多个请求方法中,同用一个或多个设置好的序列化器,一次定义,多个请求方法通过一个方法就可以获取。通用、精简了代码
  • 提供了查询数据库 (同一个类视图多个请求方法中,同用一个模型对象,同用一个模型对象,一次定义,多个请求方法通过一个方法就可以获取。通用、精简了代码)

1、操作序列化器

        1)serialzer_class属性:

         继承GenericAPIView时通过此属性设置序列化器

        2)get_serializer_class方法

         判断是否设置serialzer_class,返回serialzer_class

    def get_serializer_class(self):
        """
        Return the class to use for the serializer.
        Defaults to using `self.serializer_class`.

        You may want to override this if you need to provide different
        serializations depending on the incoming request.

        (Eg. admins get full serialization, others get basic serialization)
        """
        assert self.serializer_class is not None, (
            "'%s' should either include a `serializer_class` attribute, "
            "or override the `get_serializer_class()` method."
            % self.__class__.__name__
        )

        return self.serializer_class

        3)get_serializer方法

         获取设置的序列化器对象

    def get_serializer(self, *args, **kwargs):
        """
        Return the serializer instance that should be used for validating and
        deserializing input, and for serializing output.
        """
        serializer_class = self.get_serializer_class()
        # 在调用该方法获取序列化器时,默认为序列化器的context属性设置三个数据
        kwargs.setdefault('context', self.get_serializer_context())
        return serializer_class(*args, **kwargs)

    def get_serializer_context(self):
        """
        Extra context provided to the serializer class.
        """
        return {
            'request': self.request, # 请求对象
            'format': self.format_kwarg, # 前端所期望的格式
            'view': self #当前请求类的视图对象
        }

2、查询数据库

        1)queryset属性

        设置模型对象 :model.objects

        2)get_queryset方法

        判断queryset属性是否设置,判断queryset是否为模型对象,返回该模型对象的所有数据

       def get_queryset(self):
        """
        Get the list of items for this view.
        This must be an iterable, and may be a queryset.
        Defaults to using `self.queryset`.

        This method should always be used rather than accessing `self.queryset`
        directly, as `self.queryset` gets evaluated only once, and those results
        are cached for all subsequent requests.

        You may want to override this if you need to provide different
        querysets depending on the incoming request.

        (Eg. return a list of items that is specific to the user)
        """
        assert self.queryset is not None, (
            "'%s' should either include a `queryset` attribute, "
            "or override the `get_queryset()` method."
            % self.__class__.__name__
        )

        queryset = self.queryset
        if isinstance(queryset, QuerySet):
            # Ensure queryset is re-evaluated on each request.
            queryset = queryset.all()
        return queryset

        3)  lookup_field常量

        设置在路由匹配时传入的路径参数标识符

        

 

         4)get_object方法

        通过lookup_field设置的路径参数标识符以及传入的路径参数,查询某一个详情的数据模型对象,不存在返回404,存在返回。

    def get_object(self):
        """
        Returns the object the view is displaying.

        You may want to override this if you need to provide non-standard
        queryset lookups.  Eg if objects are referenced using multiple
        keyword arguments in the url conf.
        """
        queryset = self.filter_queryset(self.get_queryset())

        # Perform the lookup filtering.
        lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field

        assert lookup_url_kwarg in self.kwargs, (
            'Expected view %s to be called with a URL keyword argument '
            'named "%s". Fix your URL conf, or set the `.lookup_field` '
            'attribute on the view correctly.' %
            (self.__class__.__name__, lookup_url_kwarg)
        )

        filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
        obj = get_object_or_404(queryset, **filter_kwargs)

        # May raise a permission denied
        self.check_object_permissions(self.request, obj)

        return obj

3、测试

        1)定义的序列化器

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

        2)视图的定义

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):
    queryset = BookInfo.objects
    serializer_class = BookSerializer
    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)

        3)路由的定义

from django.urls import path, re_path

from .views import *

urlpatterns = [

    # ---------------------GenericsView----------------------------
    re_path(r'^demo/books/(?P<pk>\d+)/$', BookGenericAPIView.as_view()),
    path('demo/books/', BooksGenericAPIView.as_view())
]

 

三、重写get_serializer_class()方法使用多个序列化器

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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值