drf之请求与响应

继承APIView后,请求对象request中,每一次请求都是一个新的request

  • Request类:属性或方法
    1.REST framework传入视图的request对象不再是django默认的HttpResquest对象,而是REST framework提供的扩展了HttpResquest类的Request类的对象。
    2.REST framework提供了Parser解析器,在接收到请求后会自动根据Content-Type,指名的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为字典[QueryDict]对象保存到Request对象中。
    3.Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果
    4.无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据
  • Data
    1.request.data返回解析之后的请求体数据。类似于django中标准的request.POST和request.FILES属性,但提供如下特性:
    2.包含了解析之后的文件和非文件数据
    3.包含了对POST、PUT、PATCH请求方式解析的数据
    4.利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据

注意:原生djagno,put提交的数据在request.POST中是取不到的

  • Query_params
    其他的用起来跟之前一样用(FILES,method,path....)底层原理 __getattr__

Response类

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

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

  • 参数说明
data=None,    # 字典,列表 序列化成json格式字符串,返回给前端(放在http响应的body中了)
status=None,  # http 响应的状态码,默认是200,201
     drf帮咱们把所有的http响应状态码都做成了常量,可以直接导进来用
headers=None, # http的响应头,字典 {name:lqz}
template_name=None, # 了解:在浏览器中看到好看的页面,指定的模板
content_type=None,  # 响应的编码格式(json)
  • 原生django要在响应头中加数据
dic = {'name':'joker','age':18}
res = JsonResponse(d)
res['rrr'] = 'yyyy'
return res
  • 配置
    可以在rest_framework.settings查找所有的drf默认配置项
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
        'rest_framework.renderers.JSONRenderer',  # json渲染器
        'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览API渲染器
    )
}

drf能够解析的请求编码,响应编码

能够解析的请求编码

  • 默认能解析:
    urlencoded
    form-data
    json

项目中没有配置,是因为在drf内置的配置文件中提前配好了
drf也是有两套,一套是项目中的配置(settings.py),一套是默认的配置
drf的配置文件settings.py中有DEFAULT_PARSER_CLASSES(默认的解析类)

'rest_framework.parsers.JSONParser',     # 可以解析json格式
'rest_framework.parsers.FormParser',     # 可以解析urlencoded格式
'rest_framework.parsers.MultiPartParser' # 可以解析form-data格式

想让我们的接口只能接受json格式

  • 方式一:全局配置,到项目配置文件。以后所有的接口都遵循这个配置
REST_FRAMEWORK = {
            'DEFAULT_PARSER_CLASSES': [
                'rest_framework.parsers.JSONParser',
                'rest_framework.parsers.FormParser',
                # 'rest_framework.parsers.MultiPartParser',  # 不支持form-data格式
                ],
            }
  • 方式二:局部配置
class TestView(APIView):
    parser_classes = [JSONParser,FormParser,MultiPartParser]  # 在视图类中指定json格式编码格式,后续配置文件,drf配置文件的设置都失效

总结:
解析类的使用顺序:优先用视图类自己的,然后用项目配置文件,最后用内置的
实际项目如何配置
基本上都运行JSONParser,FormParser
如果上传文件只允许MultiPartParser

响应编码

如果用浏览器有好看的样子,如果用postman只看到json格式
默认请情况下,响应的编码是根据客户端类型决定的

  • 全局配置:在项目的配置文件
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [
    # 'rest_framework.renderers.JSONRenderer',  # json格式
    'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览器的格式
        ]
    }
  • 局部配置:
class TestView(APIView):
    renderer_classes = [JSONRenderer,]

实际编码中,响应一般步配,就用默认

drf之视图组件

由于drf提供了一个顶层的视图类APIView,咱们可以通过继承APIView写视图类
后期咱们要写的代码可能重复代码比较多,就可以使用面向对象的继承,封装

两个视图基类

  • APIView
  • GenericAPIView(继承了APIView)

APIView

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

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

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

GenericAPIView

GenericAPIView--->继承了APIView

类属性
	queryset = User.objects.all()  # 指明使用的数据查询集
	serializer_class = UserSerializer  # 指明视图使用的序列化器
方法
	self.get_object() # 根据pk获取单个数据
	self.get_serializer # 获取要使用的序列化类
	self.get_queryset() # 获取所有要序列化数据

基于APIView写5个接口

class UserView(GenericAPIView):
    # 配置两个 类属性
    queryset = User.objects.all()
    serializer_class = UserSerializer

    # def get_queryset(self):
    #     if self.request.method=='GET':
    #         return User.objects.all()
    #     else:
    #         return Publish.object.all()

    def get(self, request):
        res_list = self.get_queryset()  # 提高扩展性
        ser = self.get_serializer(instance=res_list, many=True)
        return Response(ser.data)

    def post(self, request):
        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': "新增成功"}, status=201)
        else:
            return Response({'code': 101, 'msg': ser.errors})


class UserDetailView(GenericAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    def get(self, request, pk):
        # obj = self.get_queryset().filter(pk=pk).first()
        # queryset.get({'pk':'有名分组分出来的'}
        obj = self.get_object()  # 根据传入的pk,获取一条数据
        ser = self.get_serializer(instance=obj)
        return Response(ser.data)

    def put(self, request, pk):
        obj = self.get_object()
        ser = self.get_serializer(instance=obj, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': "修改成功"}, status=201)
        else:
            return Response({'code': 101, 'msg': ser.errors})

    def delete(self, request, pk):
        self.get_queryset().filter(pk=pk).delete()
        return Response('')

基于GenericAPIView写5个接口

必须配合GenericAPIView使用,不能配合APIView使用

from rest_framework.mixins import RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, \
    ListModelMixin

"""
CreateModelMixin:写了一个Create方法,就是原来咱们post中的代码
RetrieveModelMixin:retrieve,就是咱们原来的get
UpdateModelMixin:update方法,就是咱们原来的put
ListModelMixin:list方法,就是原来咱们的get
DestroyModelMixin:destroy方法,就是原来咱们的delete
"""
class UserView(GenericAPIView, ListModelMixin, CreateModelMixin):
    # 配置两个 类属性
    queryset = User.objects.all()
    serializer_class = UserSerializer

    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 UserDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    def get(self,request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args,**kwargs):
        return self.update(request,*args,**kwargs)

    def delete(self, request, *args,**kwargs):
        return self.destroy(request,*args,**kwargs)

9个视图子类

from rest_framework.generics import ListAPIView,CreateAPIView,   RetrieveAPIView,DestroyAPIView,UpdateAPIView
from rest_framework.generics import ListCreateAPIView,     RetrieveUpdateDestroyAPIView,RetrieveUpdateAPIView,RetrieveDestroyAPIView
# 正常来讲  Destroy+Update 应该有一个 作者没加
class UserView(ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
class UserDetailView(RetrieveUpdateDestroyAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

视图集

继承ModelViewSet编写5个接口

  • 视图类
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
class UserView(ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
  • 路由
path('user/', views.UserView.as_view({'get': 'list', 'post': 'create'})),
path('user/<int:pk>', views.UserView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),

源码分析ViewSetMixin

@classonlymethod
def as_view(cls, actions=None, **initkwargs):
    # 路由中as_view中必须传参数,必须传字典:{'get': 'list', 'post': 'create'}
    if not actions: 
        raise TypeError("The `actions` argument must be provided when "
                        "calling `.as_view()` on a ViewSet. For example "
                        "`.as_view({'get': 'list'})`")
    # 路由匹配成功,执行view(request),request是老的request
    def view(request, *args, **kwargs):
        # actions={'get': 'list', 'post': 'create'}
        for method, action in actions.items():
            # method:get      action:list
            # self 是视图类的对象中通过反射,查找list,
            # handler视图类中的list方法
            handler = getattr(self, action)
            # 向视图类的对象中,反射 method:get,handler:list方法
            # self.get=list
            setattr(self, method, handler)
        return self.dispatch(request, *args, **kwargs)
    return csrf_exempt(view)


# 只要继承了ViewSetMixin,以后路由写法变量,都要协程:views.UserView.as_view({'get': 'list', 'post': 'create'}))
# 这样写好以后,对应的请求方式来了,就会执行配置的方法

# 扩展:
    以后只要继承了ViewSetMixin,视图类中可以写任意名字的方法,不用非得写get,post,delete

总结

#两个基类
APIView
GenericAPIView:有关数据库操作,queryset 和serializer_class


# 5个视图扩展类(rest_framework.mixins)
CreateModelMixin:create方法创建一条
DestroyModelMixin:destory方法删除一条
ListModelMixin:list方法获取所有
RetrieveModelMixin:retrieve获取一条
UpdateModelMixin:update修改一条

# 9个子类视图(rest_framework.generics)
CreateAPIView: 继承CreateModelMixin,GenericAPIView,有post方法,新增数据
DestroyAPIView:继承DestroyModelMixin,GenericAPIView,有delete方法,删除数据
ListAPIView:继承ListModelMixin,GenericAPIView,有get方法获取所有
UpdateAPIView:继承UpdateModelMixin,GenericAPIView,有put和patch方法,修改数据
RetrieveAPIView:继承RetrieveModelMixin,GenericAPIView,有get方法,获取一条


ListCreateAPIView:继承ListModelMixin,CreateModelMixin,GenericAPIView,有get获取所有,post方法新增
RetrieveDestroyAPIView:继承RetrieveModelMixin,DestroyModelMixin,GenericAPIView,有get方法获取一条,delete方法删除
RetrieveUpdateAPIView:继承RetrieveModelMixin,UpdateModelMixin,GenericAPIView,有get获取一条,put,patch修改
RetrieveUpdateDestroyAPIView:继承RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView,有get获取一条,put,patch修改,delete删除

#视图集
ViewSetMixin:重写了as_view 
ViewSet:     继承ViewSetMixin和APIView

GenericViewSet:继承ViewSetMixin, generics.GenericAPIView
ModelViewSet:继承mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin,GenericViewSet
ReadOnlyModelViewSet:继承mixins.RetrieveModelMixin,mixins.ListModelMixin,GenericViewSet
 posted on 2022-09-29 21:33  Joker_Ly  阅读(13)  评论(0)    收藏  举报