drf请求和响应、2基类、5个视图扩展类、9个视图子类
1、
1 2 3 4 5 6 7 8 9 | 视图类继承APIView后多了 - 0 去除了csrf认证 - 1 新的request - request.data - request.query_params - request.其他跟之前一样 - request._request 是老的 - 2 三大认证 - 3 全局异常 |
JSONParser: 解析json格式
FormParser: 默认的编码 urlencoded
MultiPartParser: 传文件格式 form-data
1 2 3 4 | from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.parsers import JSONParser, FormParser, MultiPartParser from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer |
局部限制
写一个类属性 parser_classes = [JSONParser或者FormParser、MultiPartParser]
1 2 3 4 5 6 7 8 9 10 11 12 13 | class BookView(APIView): # 类属性 parser_classes = [JSONParser] def get( self , request): res = Response(data = { 123 }, status = 500 , headers = { 'xxx' : 'yyy' }) print (res.data) return res def post( self , request): print ( self .parser_classes) print (request.data) return Response( '新增' ) |
效果:
全局限制
1 2 3 4 5 6 7 8 9 10 11 12 13 | REST_FRAMEWORK = { #####请求体的限制 'DEFAULT_PARSER_CLASSES' : [ 'rest_framework.parsers.JSONParser' , 'rest_framework.parsers.FormParser' , # 'rest_framework.parsers.MultiPartParser' ], #####响应格式的限制 'DEFAULT_RENDERER_CLASSES' : [ 'rest_framework.renderers.JSONRenderer' , 'rest_framework.renderers.BrowsableAPIRenderer' , ], } |
补充:
全局使用后,局部再限制---》只需要在视图类上加即可
全局如果用了,局部这样配,优先用局部的,也就是这个类管理的接口,只能接收form-data格式 parser_classes = [MultiPartParser]
二、
1、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # from rest_framework.response import Response ### __init__ 中需要传这几个参数,不传也可以 data = None # 字典,列表,字符串,空赋值给它---》http响应体中 ---》第一个参数是它 status = None , # http响应状态码,默认是200,千万不能写成1xx headers = None , # http响应头,后期我们可以往响应头中放数据 content_type = None # 响应编码格式(不用管,用浏览器访问就是:text/html,用postman就是:json格式) template_name = None # 模版名字 默认是:rest_framework/api.html 了解,可以定制自己返回的页面样子 ###补充:后面会用---》通过res.data 就能取到当时放的datga res = Response(data = {},status = 500 ,headers = { 'xxx' : 'yyy' }) print (res.data) return res ### 补充:取当时放的响应头 res.headers 拿不到数据,可以通过下面的方式或得到 print (res[ 'xxx' ]) print (res.has_header( 'zzz' )) |
serializer 类中序列化后的字段,通过 Response(ser.data)第一个参数赋值给data
1 2 | publish_detail = serializers.DictField(read_only = True ) author_list = serializers.ListField(read_only = True ) |
2、
响应有编码格式:默认支持json和text/html(浏览器)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 修改只支持json ### 局部使用 class BookView(APIView): renderer_classes = [BrowsableAPIRenderer] ### 全局使用 REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES' : [ 'rest_framework.renderers.JSONRenderer' , 'rest_framework.renderers.BrowsableAPIRenderer' , ], } ##局部禁用---》全局已经配置了---》局部想用浏览器的样子 class BookView(APIView): renderer_classes = [BrowsableAPIRenderer] # 如果不配置---》有默认 - 解析:三种编码都能解析 - 响应:浏览器访问看到浏览器的样子,postman访问,看到json格式 |
3、基于原生的django,向响应头写入数据
1 2 3 4 5 6 7 8 9 10 | from django.http import HttpResponse def custom_header_view(request): # 创建一个HttpResponse对象 response = HttpResponse( "Hello, World!" ) # 向响应头添加自定义信息 response[ 'X-Custom-Header' ] = 'this is a test' return response |
三、两个基类APIView和GenericAPIView
基于 GenericAPIView 写接口
1、GenericAPIView 源码内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # GenericAPIView 有类属性和方法 ### 重要属性### - queryset:以后放所有某个表查询出的数据 - serializer_class:要序列化的类 ### 重要方法### - get_queryset :要序列化的所有数据,qs对象 - get_serializer :序列化类 - get_object :修改,查询的单条 ## 了解类属性: - lookup_field = 'pk' 路由使用转换器,转换出来的参数,查询单条要用到,如果改了,路由对应也要修改,一般不改 - filter_backends:后面详细讲 过滤 功能 - pagination_class :后面详细讲 分页 ### 了解方法 - get_serializer_class 后期咱们可能会重写它,指定某些方法使用不同的序列化类 - filter_queryset 后面跟过滤功能一起讲 |
补充:手写GenericAPIView
两个类属性,三个方法
1 2 3 4 5 6 7 8 9 10 11 12 13 | class GenericAPIView(APIView): queryset = None serializer_class = None def get_queryset( self ): return self .queryset. all () # 真正使用的时候,再加all获取所有才行 def get_serializer( self , * args, * * kwargs): return self .serializer_class( * args, * * kwargs) def get_object( self , pk): res = self .get_queryset() return res. filter (pk = pk).first() |
2、案例代码
view
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | class PublishView(GenericAPIView): # 定义两个类属性,方便用的时候进行替换 queryset = Publish.objects. all () serializer_class = PublishSerializer def get( self , request): obj_list = self .get_queryset() ser = self .get_serializer(instance = obj_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' : 200 , "data" : ser.data, 'msg' : "添加成功" }) else : return Response(ser.errors) class PublishDetailView(GenericAPIView): queryset = Publish.objects. all () # 表数据查询结果 serializer_class = PublishSerializer # 序列化实例 def get( self , request, pk): obj = self .get_object() 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' : 200 , "data" : ser.data, 'msg' : "修改成功" }) return Response(ser.errors) def delete( self , request, pk): self .get_object().delete() return Response( '删除成功!' ) |
注意:
-get_object方法 :修改,查询单条、删除使用
serializer
1 2 3 4 5 | class PublishSerializer(serializers.ModelSerializer): class Meta: model = Publish # fields = '__all__' fields = [ 'name' , 'addr' ] |
四、五
ListModelMixin :查询所有记录
CreateModelMixin:新增记录
UpdateModelMixin:修改某一条记录
DestroyModelMixin:删除某一条记录
RetrieveModelMixin:查询一条记录
1、view
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, \ RetrieveModelMixin class PublishView(GenericAPIView, ListModelMixin, CreateModelMixin): queryset = Publish.objects. all () serializer_class = PublishSerializer def get( self , request): return self . list (request) def post( self , request): return self .create(request) class PublishDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): queryset = Publish.objects. all () serializer_class = PublishSerializer def put( self , request, pk): return self .update(request, pk) def get( self , request, pk): return self .retrieve(request, pk) def delete( self , request, pk): return self .destroy(request, pk) |
补充:ListModelMixin 扩展类的源码,里面用到了GenericeAPIView的get_queryset()、get_serializer() 两个方法。
在视图类中 return self.list(request) 就是利用ListModelMixin 扩展类做了序列化和反序列化操作、resturn Response(serizlizer.data)
1 2 3 4 5 6 7 8 9 10 | def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_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、serializer
1 2 3 4 5 | class PublishSerializer(serializers.ModelSerializer): class Meta: model = Publish # fields = '__all__' fields = [ 'name' , 'addr' ] |
五、九个视图子类
1、九个视图子类分类
不带pk的
ListAPIView, CreateAPIView, ListCreateAPIView
带pk的
RetrieveAPIView, UpdateAPIView, DestroyAPIView
RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView, RetrieveUpdateAPIView
2、有了这九个视图子类可以大大减少代码量
导入:九个视图子类有继承 GenericAPIView,它们都可以从.generics 里导入
from rest_framework.generics import ListCreateAPIView
1 2 3 4 5 6 7 | class PublishView(ListAPIView, ListCreateAPIView, CreateAPIView): queryset = Publish.objects. all () serializer_class = PublishSerializer class PublishDetailView(RetrieveUpdateDestroyAPIView): queryset = Publish.objects. all () serializer_class = PublishSerializer |
注:
以后想写5个接口中的某一个或某几个或所有,只需要选择继承不同的类即可,类中只需要配置两个类属性
没有继承的类相应的接口就没法使用
3、路由和序列化文件不变和之前写法一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ###路由 from django.urls import path from app01.views import PublishView, PublishDetailView urlpatterns = [ path( 'publishs/' , PublishView.as_view()), path( 'publishs/<int:pk>' , PublishDetailView.as_view()), ] ###序列化文件 class PublishSerializer(serializers.ModelSerializer): class Meta: model = Publish # fields = '__all__' fields = [ 'name' , 'addr' ] |