drf-GenericAPIView

发布时间 2023-09-04 21:17:30作者: Way*yy

drf请求

1.1drf请求之Request类

# from rest_framework.request import Request


# 1 以后视图类的方法中的request都是这个类的对象
# 2 以后使用request.data  取请求体中的数据
# 3 以后使用request.query_params  取请参数中的数据
# 4 以后其他属性,用起来跟之前一样--->重要
为什么我还可以直接使用request.method方法?
	当我request.method 的时候--->实际上底层会反射出来 request._request.'method'
    -这个类from rest_framework.request import Request没有method,他会触发这个类的__getattr__
    
# 5 FILES 用起来跟之前一样,前端传入的文件在里面

1.2控制前端请求编码格式

针对前端传入的编码:urlencoded、form-data、josn
# 某些接口只做josn格式的接收、某些接口只做urlencoded格式的接收、某些接口只做form-data格式的接收,该怎么去做?这时候就用到了,控制前端传的编码格式了
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
JSONParser:只能传json
FormParser:只能传urlencoded
MultiPartParser:只能传form-data

方法一:# 在视图函数内局部使用,局部使用优先与全部使用
class BookView(APIView):
    parser_classes = [FormParser] # 设置这个是视图类只能接收urlencoded格式的数据
    
方法二:全局生效----->所有接口只能支持一种或两种数据格式
	在配置文件中添加配置
    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES': [
            'rest_framework.parsers.JSONParser',
            'rest_framework.parsers.FormParser',
            # 'rest_framework.parsers.MultiPartParser'
        # 所有接口仅支持josn跟urlencoded
        ]
    }
    
方法三:全局使用以后局部限制------>只需要在视图类中添加即可
class BookView(APIView):  # 全局如果用了,局部这样配,优先用局部的,也就是这个类管理的接口,只能接收form-data格式
    parser_classes = [MultiPartParser]
    
    
我们什么都没配置为什么还能接收三种格式的数据?
	因为在drf内部的配置文件中为我们做了这些事情

drf响应

2.1drf之Response对象源码

模块:# from rest_framework.response import Response
在Response内部的__init__的形参中有几个参数:
data:响应体中的数据
status:响应状态码 ,注意响应状态码千万不能写成1XX
template_name:模版名称,默认是:rest_framework/api.html  了解,可以定制自己返回的页面样子
headers:响应头
content_type:响应的数据格式


补充:
    res = Response(data={}, status=200, headers={"xxxx": "yyyyy"})
    print(res.data) # 获取到响应体中的数据
    res.headers # headers的数据,因为源码内部没有写
    res["xxxx"] # 获取响应头的数据
    res.has_header('zzz')# 用于检查请求头中是否存在某个特定的头部字段。这个方法返回一个布尔值
    return res

drf之响应格式

# 响应有编码格式:默认支持json和text/html(浏览器)

# 局部使用:
如果我只想支持josn
from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
class BookView(APIView): # 这个视图类只支持josn
    renderer_classes = [JSONRenderer]
    
# 全局使用:
在配置文件中配置##局部禁用---》全局已经配置了---》局部想用浏览器的样子
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]
    
    
解析和响应总结;
	解析:默认三种都可以解析
    	局部限制:parser_classes
        全局限制:配置文件
        全局限制加局部限制:在视图类中写parser_classes会优先局部的
    响应:默认两种都可以响应
        局部限制:renderer_classes
        全局限制:配置文件
        全局限制加局部限制:在视图类中写renderer_classes会优先局部的

两个视图基类

继承自己写的GenericAPIView(只要跟数据库打交道)

视图层

class GenericAPIView(APIView):
    queryset = None
    serializer_class = None

    def get_queryset(self):
        queryset = self.queryset
        return queryset.all() # 要以这个地方的查询为主 
        # models.Book.objects.all()

    def get_object(self, pk):
        res = self.get_queryset()
        return res.filter(pk=pk).first()
        # models.Book.objects.all().filter(pk=pk).first()

    def get_serializer(self, *args, **kwargs):
        return self.serializer_class(*args, **kwargs)


class BookThreeView(GenericAPIView):
    queryset = models.Book.objects.all()
    # 类只要加载,就会执行,查了所有数据,不能以它为准
    serializer_class = BookSerializer

    def get(self, request):
        book_obj = self.get_queryset()
        book = self.get_serializer(book_obj, many=True)
        return Response(book.data)

    def post(self, request):
        book_obj = self.get_serializer(data=request.data)
        # 方法一
        # if book_obj.is_valid():
        #     book_obj.save()
        #     return Response(book_obj.data)
        # 方法二
        book_obj.is_valid(raise_exception=True)
        book_obj.save()
        return Response(book_obj.data)


class BookThreeDetailView(GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, pk):
        book_obj = self.get_object(pk)
        book = self.get_serializer(book_obj)
        return Response(book.data)

    def put(self, request, pk):
        book_obj = self.get_object(pk)
        book = self.get_serializer(book_obj, data=request.data)
        book.is_valid(raise_exception=True)
        book.save()
        return Response(book.data)

    def delete(self, request, pk):
        self.get_object(pk).delete()
        return Response("")

序列化层

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = ["book_name", "book_price", "publish_dic", "author_list", "publish", "authors"]
        extra_kwargs = {
            # "book_name": {"max_length": 8, "min_length": 2},
            # "book_price": {"max_value": 1000, "min_length": 20},
            "publish": {"write_only": True},
            "authors": {"write_only": True},
        }

    publish_dic = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)

路由层

urlpatterns = [
    path('booksthree/', BookThreeView.as_view()),
    path('booksthree/<int:pk>', BookThreeDetailView.as_view()),

]

继承drf中的GenericAPIView写的

from rest_framework.generics import GenericAPIView


class BookTwoView(GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request):
        book_obj = self.get_queryset()
        book = self.get_serializer(book_obj, many=True)
        return Response(book.data)

    def post(self, request):
        book = self.get_serializer(data=request.data)
        if book.is_valid():
            book.save()
            return Response({"code": 100, "msg": book.data})
        else:
            return Response({"code": 101, "msg": book.errors})


class AddTwoBookView(GenericAPIView):
    queryset = models.Book.objects
    serializer_class = BookSerializer

    def put(self, request):
        book_obj = self.get_object()
        book = self.get_serializer(book_obj)
        if book.is_valid():
            book.save()
            return Response({"code": 200, "msg": book.data})
        else:
            return Response({"code": 101, "msg": book.errors})

    def delete(self, request, pk):
        self.get_object().delete()
        return Response({"code": 100, "msg": "删除成功"})

GenericAPIView 有类属性和方法

重要属性:
	queryset:放的是表中查询出来的所有数据
    serializer_class:序列化的类
重要方法:
	get_queryset:要序列化的所有数据,是QuerySet对象
    get_serializer :序列化类
    get_object:修改、查询涉及到单条数据
了解属性:
	lookup_field = "pk":路由使用转换器,转换出来的参数,查询单条的时候要用到,如果改了,对应的路由也要改
    filter_backends:过滤功能
	pagination_class:分页功能
了解方法:
	get_serializer_class:后期可能会重写此方法,指定某些方法使用不同的序列化类
    filter_queryset:可以对查询结果进行进一步的筛选和过滤

5个视图扩展类(不是视图类-->先继承GenericAPIView)

ListModelMixin--->查询所有,写了一个方法--->返回list,代码就是 跟咱们之前写获取单条get方法内容一样

CreateModelMixin --->新增一条,写了一个方法---->返回create,代码就是 跟咱们之前写获取单条post方法内容一样

RetrieveModelMixin --->查询一条,写了一个方法--->返回retrieve,代码就是 跟咱们之前写获取单条get方法内容一样

UpdateModelMixin --->修改一条,写了一个方法--->返回updata,代码就是 跟咱们之前写获取单条put方法内容一样

DestroyModelMixin --->删除一条,写了一个方法---->返回destroy,代码就是 跟咱们之前写获取单条delete方法内容一样

# 为什么写5个,不写俩?
	因为后期不一定 5个接口都写

视图类

class BookThreeView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializer

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

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


class BookThreeDetailView(GenericAPIView, DestroyModelMixin, UpdateModelMixin, RetrieveModelMixin):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializer

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

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

    def delete(self, request):
        return self.destroy(request)
    
				"只有视图类在变其他都不会变"

作业

#1  原生django,向响应头写入数据

#2 测试 请求编码格式局部配置和全局配置是否生效

#3 编写局部和全局使用响应编码格式

#4 基于APIView写Book 5个接口
# 5 基于GenericAPIView 写publish5个接口
# 6 基于 5个视图扩展类(不是视图类--》先继承GenericAPIView)
--------

# 7 基于9个视图子类 写5个接口

1 原生django,向响应头写入数据

在原生Django中可以通过设置HttpResponse对象的header属性,可以添加自定义的响应头字段。
from django.http import HttpResponse

def my_view(request):
    response = HttpResponse()
    response['X-Custom-Header'] = 'Custom Value'
    return response

2 测试 请求编码格式局部配置和全局配置是否生效

![](C:\Users\17284\Pictures\Screenshots\屏幕截图 2023-09-04 155530.png)

3、编写局部和全局使用响应编码格式

3.1、解析局部:

class BookView(APIView):
    parser_classes = [JSONParser]

3.2、响应局部:

class BookView(APIView):
    renderer_classes = [JSONRenderer]

3.3、解析全局:

    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES': [
            'rest_framework.parsers.JSONParser',
            'rest_framework.parsers.FormParser',
            'rest_framework.parsers.MultiPartParser'
        ]
    }

3.4、响应全局:

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ],
}

4、基于APIView写Book 5个接口

class BookView(APIView):
    parser_classes = [JSONParser]
    renderer_classes = [JSONRenderer]

    def get(self, request):
        book_obj = models.Book.objects.filter(is_delete=0).all()
        book = BookSerializer(instance=book_obj, many=True)
        return Response(book.data)

    def post(self, request):
        book = BookSerializer(data=request.data)
        if book.is_valid():
            book.save()
            return Response({"code": 100, "msg": book.data})
        else:
            return Response({"code": 101, "msg": book.errors})
            # res = Response(data={}, status=200, headers={"xxxx": "yyyyy"})
            # print(res.data)
            # return res


class AddBookView(APIView):
    def get(self, request, pk):
        book_obj = models.Book.objects.filter(pk=pk).filter()
        book = BookSerializer(instance=book_obj[0])
        return Response(book.data)

    def put(self, request, pk):
        book_obj = models.Book.objects.filter(pk=pk).first()
        book = BookSerializer(book_obj, data=request.data)
        if book.is_valid():
            book.save()
            return Response({"code": 200, "msg": book.data})
        else:
            return Response({"code": 101, "msg": book.errors})

    def delete(self, request, pk):
        models.Book.objects.filter(pk=pk).update(is_delete=1)
        return Response({"code": 200, "msg": "删除成功"})

5、基于GenericAPIView 写publish5个接口

视图类
class GenericAPIView(APIView):
    queryset = None
    serializer_class = None

    def get_queryset(self):
        queryset = self.queryset
        return queryset.all()
        # models.Book.objects.all()

    def get_object(self, pk):
        res = self.get_queryset()
        return res.filter(pk=pk).first()
        # models.Book.objects.all().filter(pk=pk).first()

    def get_serializer(self, *args, **kwargs):
        return self.serializer_class(*args, **kwargs)


class BookThreeView(GenericAPIView):
    queryset = models.Publish.objects.all()
    serializer_class = BookSerializer

    def get(self, request):
        book_obj = self.get_queryset()
        book = self.get_serializer(book_obj, many=True)
        return Response(book.data)

    def post(self, request):
        book_obj = self.get_serializer(data=request.data)
        # 方法一
        # if book_obj.is_valid():
        #     book_obj.save()
        #     return Response(book_obj.data)
        # 方法二
        book_obj.is_valid(raise_exception=True)
        book_obj.save()
        return Response(book_obj.data)


class BookThreeDetailView(GenericAPIView):
    queryset = models.Publish.objects.all()
    serializer_class = BookSerializer

    def get(self, request, pk):
        book_obj = self.get_object(pk)
        book = self.get_serializer(book_obj)
        return Response(book.data)

    def put(self, request, pk):
        book_obj = self.get_object(pk)
        book = self.get_serializer(book_obj, data=request.data)
        book.is_valid(raise_exception=True)
        book.save()
        return Response(book.data)

    def delete(self, request, pk):
        self.get_object(pk).delete()
        return Response("")
序列化
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Publish
        fields = "__all__"

6 基于 5个视图扩展类(不是视图类--》先继承GenericAPIView)

视图类
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin, DestroyModelMixin, \
    UpdateModelMixin
    
    
class BookThreeView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializer

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

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


class BookThreeDetailView(GenericAPIView, DestroyModelMixin, UpdateModelMixin, RetrieveModelMixin):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializer

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

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

    def delete(self, request):
        return self.destroy(request)

序列化类
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = ["book_name", "book_price", "publish_dic", "author_list", "publish", "authors"]
        extra_kwargs = {
            # "book_name": {"max_length": 8, "min_length": 2},
            # "book_price": {"max_value": 1000, "min_length": 20},
            "publish": {"write_only": True},
            "authors": {"write_only": True},
        }

    publish_dic = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)

7 基于9个视图子类 写5个接口

class CreateAPIView(CreateModelMixin, GenericAPIView):
    def post(self, request):
        """
            添加一条
        :param request: 
        :return: 
        """
        return self.create(request)


class ListAPIView(ListModelMixin, GenericAPIView):
    def get(self, request):
        """
            查看所有
        :param request: 
        :return: 
        """
        return self.list(request)


class RetrieveAPIView(RetrieveModelMixin, GenericAPIView):
    def get(self, request):
        """
        查看单条
        :param request: 
        :return: 
        """
        return self.retrieve(request)


class DestroyAPIView(DestroyModelMixin, GenericAPIView):
    def delete(self, request):
        """
        删除一条
        :param request: 
        :return: 
        """
        return self.destroy(request)


class UpdateAPIView(UpdateModelMixin, GenericAPIView):
    def put(self, request):
        """
        修改一条
        :param request: 
        :return: 
        """
        return self.update(request)


class ListCreateAPIView(ListModelMixin, CreateModelMixin, GenericAPIView):
    # 查看所有、新增一条
    def get(self, request):
        return self.list(request)

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


class RetrieveUpdateAPIView(RetrieveModelMixin, UpdateModelMixin, GenericAPIView):
    # 查看一条、修改一条
    def get(self, request):
        return self.retrieve(request)

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


class RetrieveDestroyAPIView(RetrieveModelMixin, DestroyModelMixin, GenericAPIView):
    # 查看一条、删除一条
    def get(self, request):
        return self.retrieve(request)

    def delete(self, request):
        return self.destroy(request)


class RetrieveUpdateDestroyAPIView(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    # 查看一条、修改一条、删除一条
    def get(self, request):
        return self.retrieve(request)

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

    def delete(self, request):
        return self.destroy(request)