Python笔记_62_Django-DRF(视图相关)_请求与响应_视图类_View_APIView_GenericView

Django-DRF(视图相关)

drf除了在数据序列化部分简写代码以外,还在视图中提供了简写操作。所以在django原有的django.views.View类基础上,drf封装了多个子类出来提供给我们使用。

请求与响应

Request

REST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。
REST framework 提供了Parser解析器,Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。

无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。

  • request.data 返回解析之后的请求体数据。类似于Django中标准的 request.POSTrequest.FILES 属性.

    • 包含了解析之后的文件和非文件数据

    • 包含了对POSTPUTPATCH请求方式解析后的数据

    • 利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据

  • request.query_params与Django标准的 request.GET 相同,只是更换了更正确的名称而已。

Response

from rest_framework.response import Response
REST framework提供了一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型

REST framework提供了 Renderer 渲染器,用来根据请求头中的Accept(接收数据类型声明)来自动转换响应数据到对应格式。如果前端请求中未进行Accept声明,则会采用默认方式处理响应数据,我们可以通过配置来修改默认响应格式。

可以在rest_framework.settings查找所有的drf默认配置项

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
        'rest_framework.renderers.JSONRenderer',  # json渲染器
        'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览API渲染器
    )
}

构造方式:
Response(data, status=None, template_name=None, headers=None, content_type=None)

常用属性(用的不多):

  1. data:传给response对象的序列化后,但尚未render处理的数据
  2. status_code:状态码的数字
  3. content:经过render处理后的响应数据
状态码

REST Framework在rest_framework.status模块中提供了常用状态码常量。

  • 信息告知—1XX
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
  • 成功—2XX
HTTP_200_OK
HTTP_201_CREATED
HTTP_202_ACCEPTED
HTTP_203_NON_AUTHORITATIVE_INFORMATION
HTTP_204_NO_CONTENT
HTTP_205_RESET_CONTENT
HTTP_206_PARTIAL_CONTENT
HTTP_207_MULTI_STATUS
  • 重定向—3XX
HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT
  • 客户端错误—4XX
HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_402_PAYMENT_REQUIRED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_406_NOT_ACCEPTABLE
HTTP_407_PROXY_AUTHENTICATION_REQUIRED
HTTP_408_REQUEST_TIMEOUT
HTTP_409_CONFLICT
HTTP_410_GONE
HTTP_411_LENGTH_REQUIRED
HTTP_412_PRECONDITION_FAILED
HTTP_413_REQUEST_ENTITY_TOO_LARGE
HTTP_414_REQUEST_URI_TOO_LONG
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
  • 服务器错误—5XX
HTTP_500_INTERNAL_SERVER_ERROR
HTTP_501_NOT_IMPLEMENTED
HTTP_502_BAD_GATEWAY
HTTP_503_SERVICE_UNAVAILABLE
HTTP_504_GATEWAY_TIMEOUT
HTTP_505_HTTP_VERSION_NOT_SUPPORTED
HTTP_507_INSUFFICIENT_STORAGE
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED

视图

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

  1. 控制序列化器的执行(检验、保存、转换数据)
  2. 控制数据库查询的执行
View

views.py

from django.views import View


class Student1View(View):
    def get(self, request):
        print(request)  # <WSGIRequest: GET '/req/student1/'>
        print(request.GET)

        data_dict = {'name': "zhangguocheng", "age": "18"}

        return JsonResponse(data_dict)

urls.py

urlpatterns = [
    # 区分View与APIView
    path("student1/", views.Student1View.as_view()),
    ]
APIView

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

APIView 与View的不同之处在于:

  1. 传入到视图方法中的是REST framework的request对象,而不是Django的HttpRequest对象;
  2. 视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;
  3. 任何APIException异常都会被捕获到,并且处理成合适的响应信息;
  4. 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。

支持定义的类属性:authentication_classes —列表或元祖,身份认证类、permissoin_classes —列表或元祖,权限检查类、throttle_classes —列表或元祖,流量控制类

对比View

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status


class Student2APIView(APIView):
    def get(self, request):
        print(request)  # <rest_framework.request.Request object at 0x7f3893aabfd0>
        print(request.query_params)

        data_dict = {'name': "zhangguocheng", "age": "18"}

        return Response(data_dict, status=status.HTTP_204_NO_CONTENT, headers={"name": "xiaobai"})

urls.py

urlpatterns = [
    # 区分View与APIView
    path("student2/", views.Student2APIView.as_view()),
    ]

实现接口:
views.py

"""
使用APIView提供学生信息的5个API接口
GET    /req/student3/               # 获取全部数据
POST   /req/student3/               # 添加数据

GET    /req/student3/(?P<pk>\d+)/    # 获取一条数据
PUT    /req/student3/(?P<pk>\d+)/    # 更新一条数据
DELETE /req/student3/(?P<pk>\d+)/    # 删除一条数据
"""
from students.models import Student
from req.serializers import StudentModelSerializer


class Student3APIView(APIView):
    def get(self, request):
        "获取所有数据"
        student_list = Student.objects.all()

        serializer = StudentModelSerializer(instance=student_list, many=True)

        return Response(serializer.data)


    def post(self, request):
        # 获取用户提交的数据
        data_dict = request.data

        serializer = StudentModelSerializer(data=data_dict)

        # 数据校验
        serializer.is_valid(raise_exception=True)

        # 数据保存
        serializer.save()

        return Response(serializer.data)



class Student4APIView(APIView):
    def get(self, request, pk):
        """获取pk值对应的模型对象"""
        student_obj = Student.objects.get(pk=pk)

        serializer = StudentModelSerializer(instance=student_obj)

        return Response(serializer.data)

    def put(self, request, pk):
        student_obj = Student.objects.get(pk=pk)

        serializer = StudentModelSerializer(instance=student_obj, data=request.data)

        serializer.is_valid(raise_exception=True)

        serializer.save()

        return Response(serializer.data)

    def delete(self, request, pk):
        Student.objects.filter(pk=pk).delete()

        return Response(status=status.HTTP_204_NO_CONTENT)

urls.py

urlpatterns = [
    # 使用APIView实现接口
    path("student3/", views.Student3APIView.as_view()),
    re_path("^student3/(?P<pk>\d+)/$", views.Student4APIView.as_view()),
    ]
GenericAPIView(通用视图类)
  • 提供的关于序列化器使用的属性与方法:

    • serializer_class 指明视图使用的序列化器
    • get_serializer_class(self) 调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中通过返回不同的序列化器类名
    • get_serializer(self, args, *kwargs) 返回序列化器对象
  • 提供的关于数据库查询的属性与方法

    • queryset 指明使用的数据查询集
    • get_queryset(self) 返回视图使用的查询集
    • get_object(self) 返回详情视图所需的模型类数据对象 前提: pk
  • 其他可以设置的属性

    • pagination_class 指明分页控制类
    • filter_backends 指明过滤控制后端

views.py

"""
使用GenericAPIView提供学生信息的5个API接口
GET    /req/student4/               # 获取全部数据
POST   /req/student4/               # 添加数据

GET    /req/student4/(?P<pk>\d+)/    # 获取一条数据
PUT    /req/student4/(?P<pk>\d+)/    # 更新一条数据
DELETE /req/student4/(?P<pk>\d+)/    # 删除一条数据
"""

from rest_framework.generics import GenericAPIView


class Student5GenericAPIView(GenericAPIView):

    queryset = Student.objects.all()

    serializer_class = StudentModelSerializer

    def get(self, request):
        """获取多条数据"""
        student_list = self.get_queryset()	#  模型类对象集合

        serializer = self.get_serializer(instance=student_list, many=True) #  序列化器类

        return Response(serializer.data)

    def post(self, request):

        serializer = self.get_serializer(data=request.data)

        serializer.is_valid(raise_exception=True)

        serializer.save()

        return Response(serializer.data)


class Student6GenericAPIView(GenericAPIView):
    # 获取所有的模型对象集合
    queryset = Student.objects.all()
    # 指定序列化器类
    serializer_class = StudentModelSerializer

    def get(self, request, pk):
        """参数pk名,必须要叫pk,否则会报错。"""

        student_obj = self.get_object()

        serializer = self.get_serializer(instance=student_obj)

        return Response(serializer.data)

    def put(self, request, pk):
        student_obj = self.get_object()

        serializer = self.get_serializer(instance=student_obj, data=request.data)

        serializer.is_valid(raise_exception=True)

        serializer.save()

        return Response(serializer.data)

    def delete(self, request, pk):

        student_obj = self.get_object()
        student_obj.delete()

        return Response(status=status.HTTP_204_NO_CONTENT)

urls.py

urlpatterns = [
	# 使用GenericAPIView实现接口
    path("student4/", views.Student5GenericAPIView.as_view()),
    re_path("^student4/(?P<pk>\d+)/$", views.Student6GenericAPIView.as_view()),
    ]

在这里插入图片描述

五个视图扩展类
使用GenericAPIView结合视图Mixin扩展类,快速实现数据接口的APIView
ListModelMixin 实现查询所有数据功能
CreateModelMixin 实现添加数据的功能
RetrieveModelMixin 实现查询一条数据功能
UpdateModelMixin 更新一条数据的功能
DestroyModelMixin 删除一条数据的功能

以上五个扩展类,要配合GenericAPIView使用.
views.py:

"""
ListModelMixin      实现查询所有数据功能
CreateModelMixin    实现添加数据的功能
"""
from rest_framework.mixins import ListModelMixin
from rest_framework.mixins import CreateModelMixin


class Student7GenericAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def get(self, reqeust):
        return self.list(reqeust)

    def post(self, request):
        return self.create(request)

"""
RetrieveModelMixin  实现查询一条数据功能
UpdateModelMixin    更新一条数据的功能
DestroyModelMixin   删除一条数据的功能
"""
from rest_framework.mixins import RetrieveModelMixin
from rest_framework.mixins import UpdateModelMixin
from rest_framework.mixins import DestroyModelMixin


class Student8GenericAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def get(self, request, pk):
        return self.retrieve(request)

    def put(self, request, pk):
        return self.update(request)

    def delete(self, request, pk):
        return self.destroy(request)  # 不要使用delete方法

urls.py :

urlpatterns = [
	# 使用GenericAPIView 结合mixin的扩展类 实现接口
    path("student5/", views.Student7GenericAPIView.as_view()),
    re_path("^student5/(?P<pk>\d+)/$", views.Student8GenericAPIView.as_view()),
    ]
内置的扩展子类

内置的扩展子类(不用自己写方法了)
只需声明querysetserializer_class即可.
views.py :

"""
ListAPIView      获取所有数据
CreateAPIView    添加数据
"""
from rest_framework.generics import ListAPIView, CreateAPIView

class Student9GenericAPIView(ListAPIView, CreateAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer


"""
RetrieveAPIView                 获取一条数据
UpdateAPIView                   更新一条数据
DestorAPIView                   删除一条数据
RetrieveUpdateDestoryAPIView    上面三个的缩写
"""

from rest_framework.generics import RetrieveAPIView
from rest_framework.generics import UpdateAPIView
from rest_framework.generics import DestroyAPIView
from rest_framework.generics import RetrieveUpdateDestroyAPIView


# 这两行效果一样.
# class Student10GenericAPIView(RetrieveAPIView, UpdateAPIView, DestroyAPIView):
class Student10GenericAPIView(RetrieveUpdateDestroyAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

urls.py :

urlpatterns = [
	# 使用内置的扩展子类,生成API接口
    path("student6/", views.Student9GenericAPIView.as_view()),
    re_path("^student6/(?P<pk>\d+)/$", views.Student10GenericAPIView.as_view()),
    ]
视图集

整合为一个视图类
views.py :

"""
视图集
上面5个接口使用了8行代码生成,但是我们可以发现有一半的代码重复了
所以,我们要把这些重复的代码进行整合,但是依靠原来的类视图,其实有2方面产生冲突的
1. 查询所有数据、添加数据是不需要声明pk的,而其他的接口需要      [路由冲突了]
2. 查询所有数据和查询一条数据,都是属于get请求                 [请求方法冲突了]
为了解决上面的2个问题,所以DRF提供了视图集来解决这个问题
"""

from rest_framework.viewsets import GenericViewSet
from rest_framework.viewsets import ModelViewSet
from rest_framework.mixins import ListModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, CreateModelMixin


# class Student11GenericAPIView(GenericViewSet, ListModelMixin, CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin):
class Student11GenericAPIView(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

urls.py :

urlpatterns = [
	# 视图集的使用
    path("student7/", views.Student11GenericAPIView.as_view({"get": "list", "post": "create"})),
    re_path("^student7/(?P<pk>\d+)/$", views.Student11GenericAPIView.as_view({"get": "retrieve",
                                                                              "put": "update",
                                                                              "delete": "destroy"})),
    ]
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值