63、模块与包的使用 、 反序列化校验源码分析 、 断言 、drf之请求 、drf之响应 、GenericAPIView

223 阅读16分钟

作业讲解

Views.py

from django.shortcuts import render

# Create your views here.

from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Author
from .serializer import AuthorSerializer


class AuthorsView(APIView):

    def get(self,request):
        author_list = Author.objects.all()
        ser = AuthorSerializer(instance=author_list,many=True)
        return Response({'code':100,'msg':'查询成功','data':ser.data})


    def post(self,request):
        ser = AuthorSerializer(data = request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code':100,'msg':'创建成功'})
        else:
            return Response({'code':100,'msg':'创建失败','errors':ser.errors})


class AuthorsDetail(APIView):
    def get(self,request,pk):
        author_obj = Author.objects.filter(pk=pk).first()
        ser = AuthorSerializer(instance=author_obj)
        return Response({'code':100,'msg':'查询成功','data':ser.data})


    def put(self,request,pk):
        author_obj = Author.objects.filter(pk=pk).first()
        ser = AuthorSerializer(data = request.data,instance=author_obj)
        if ser.is_valid():
            ser.save()
            return Response({'code':100,'msg':'修改成功'})
        else:
            return Response({'code':100,'msg':'修改失败','errors':ser.errors})

    def delete(self,request,pk):
        author_obj = Author.objects.filter(pk=pk).first()
        AuthorDetail.objects.filter(pk = author_obj.author_detail_id).delete()
        return Response({'code': 100, 'msg': '删除成功'})


Serializer.py


from rest_framework import serializers
from .models import Author,AuthorDetail

class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = ['name','phone','email','age']

    email = serializers.CharField(source='author_detail.email')
    age = serializers.IntegerField(source='author_detail.age')


    def create(self, validated_data):
        print(validated_data)  # {'name': 'nanananana', 'phone': '18085209', 'author_detail': {'email': '863942169@qq.com', 'age': 24}}
        author_detail = validated_data.pop('author_detail')
        print(validated_data)  # {'name': 'nanananana', 'phone': '18085209'}
        res  = AuthorDetail.objects.create(**author_detail)
        validated_data['author_detail']  = res
        author = Author.objects.create(**validated_data)

        return author


    def update(self, author, validated_data):
        print(validated_data)  # {'name': 'nanananana', 'phone': '18085209', 'author_detail': {'email': '863942169@qq.com', 'age': 24}}
        author.name = validated_data.get('name')
        author.phone = validated_data.get('phone')
        author.save()
        author.author_detail.email= validated_data.get('author_detail').get('email')
        author.author_detail.age = validated_data.get('author_detail').get('age')
        author.author_detail.save()

        return author

模块与包的使用

1.模块:一个py文件,被别的py文件导入使用,这个py文件称之为模块,运行的这个py文件称之为脚本文件
2.包:一个文件夹下有__init__.py
3.总结:
    1.导入模块有相对导入和绝对导入,绝对的路径是从环境变量开始的
  			1.相对导入:.  ..     (考虑执行文件为准)
        2.绝对导入:from ... import ...
    2.导入任何模块,如果使用绝对导入,都是从环境变量开始导入起
    3.脚本文件执行的路径,会自动加入环境变量
    4.相对导入的话,是从当前py文件开始计算的
    5.以脚本运行的文件,不能使用相对导入,只能用绝对导入
    
    ps:在统一文件下用相对导入,不同文件下用绝对导入,脚本运行文件不能使用相对导入

反序列化校验源码分析

1.序列化类的校验功能
		1.局部钩子:validate_字段名
		2.全局钩子:validate
    
2.思考:为什么在校验局部钩子和全局钩子的时候必须使用:validate_字段名,validate方法名 ---->源码

3.入口:ser.is_valid() ---> 做的校验
	继承顺序:AuthorSerializer --->ModelSerializer --->Serializer --->BaseSerializer --->Field
  
  """
  补充:
  	OOP:面向对象编程
  	AOP:面向切面编程:在程序的前期,中期,后期插入一些代码来执行
  			装饰器:实现aop的一种方式
  			钩子函数:实现aop的一种方式
  	
    写在类中的方法,只要写了,就会执行,不写就不执行
    
  """

1.ctrl+鼠标点:is_valid()

def is_valid(self, *, raise_exception=False):
  # 此时还没有validated_data,validated_data是校验成功后的数据,只有执行完才有
  if not hasattr(self, '_validated_data'):
    try:
      self._validated_data = self.run_validation(self.initial_data)
      #  self.run_validation(self.initial_data):核心,此时按住ctrl+鼠标点击是不对的--->ctrl+鼠标点击只能找当前类的父类,即Field---->正确做法:应该从根上找(self)--->发现Serializer里面有run_validation()方法
    except ValidationError as exc:
      self._validated_data = {}
      self._errors = exc.detail
    else:
      self._errors = {}

      if self._errors and raise_exception:
        raise ValidationError(self.errors)

        return not bool(self._errors)
      
ps:self.run_validation(self.initial_data):核心,此时按住ctrl+鼠标点击是不对的--->ctrl+鼠标点击只能找当前类的父类,即Field---->正确做法:应该从根上找(self)--->发现Serializer里面有run_validation()方法

2.在Serializer里找到run_validation()方法(AuthorSerializer、ModelSerializer里都没有这个方法)

    def run_validation(self, data=empty):
        value = self.to_internal_value(data)  # 局部钩子,在Serializer里找到run_validation()方法(AuthorSerializer、ModelSerializer里都没有这个方法)
        try:
            self.run_validators(value)
            value = self.validate(value)  # 全局钩子,BookSerializer只要写了,优先执行它的
            assert value is not None, '.validate() should return the validated data'
        except (ValidationError, DjangoValidationError) as exc:
            raise ValidationError(detail=as_serializer_error(exc))

        return value
      
ps:
	1.value = self.to_internal_value(data):在Serializer里找到to_internal_value()方法(AuthorSerializer、ModelSerializer里都没有这个方法),鼠标点进去

3.ctrl+鼠标点:to_internal_value(data)--->Serializer类的方法

    def to_internal_value(self, data):
        for field in fields:       # fields是序列化类中写的一个个的类字段的对象列表,一个field是name对象,field.field_name字符串:name
            validate_method = getattr(self, 'validate_' + field.field_name, None)   # self是序列化类的对象,BookSerializer的对象  validate_name
            try:
                validated_value = field.run_validation(primitive_value)  # 字段自己的校验
                if validate_method is not None:
                    validated_value = validate_method(validated_value)  # 局部钩子
            except ValidationError as exc:
                errors[field.field_name] = exc.detail
            except DjangoValidationError as exc:
                errors[field.field_name] = get_error_detail(exc)
            except SkipField:
                pass
            else:
                set_value(ret, field.source_attrs, validated_value)

        if errors:
            raise ValidationError(errors)

        return ret

总结

1.入口:ser.is_valid
2.在Serializer里找到run_validation()方法(AuthorSerializer、ModelSerializer里都没有这个方法)
3.走局部钩子的代码:是通过反射获取BookSerializer中写的局部钩子函数,如果写了,就会执行
4.走全局钩子代码:self.validate(value),只要序列化类中写了,优先走自己的

断言

1.断言:断定某个东西是我认为的,如果不是就抛异常(等同于if判断+抛异常)
2.例子
    def func(a,b):
        return a+b
    res = func(1,4)
    assert res==3,Exception('必须等于3')   # 或:assert res==3,('必须等于3')  
    print('其他操作')
    
3.asser后面是true,才能执行下面的代码,否则直接报错,程序停止运行
4.类似于:
	if not res==3:
    raise Exception('不等于3')
  print('其他操作')

drf之请求

回顾

1.已经了解到:
    1.视图类:APIView
    2.序列化组件:Serializer,ModelSerializer
    3.drf:Request类的对象
    4.drf:Response
    
2.REST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。

3.REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典[QueryDict]对象保存到Request对象中。

4.Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。

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

Request类对象的常用属性

1.data:request.data 返回解析之后的请求体数据。类似于Django中标准的request.POST和 request.FILES属性,
	提供如下特性:
    1.包含了解析之后的文件和非文件数据
    2.包含了对POST、PUT、PATCH请求方式解析后的数据
    3.利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据
    
2. .query_params
		request.query_params与Django标准的request.GET相同,只是更换了更正确的名称而已。

3. 其他属性用起来和之前一样

请求,能够接受的编码格式

1.请求,能够接受的编码格式:urlencode、form-data、json
2.如何限制只能接受某种或几种编码格式
	1.限制方式一:在视图类中写,但只是局部有效
    from rest_framework.parsers import JSONParser,FormParser,MultiPartParser

    class BookView(APIView):
        parser_classes = [JSONParser,FormParser]
        def get(self,request):
          pass
        ...
  
	2.限制方式二:在配置文件中写--->全局有效    
    在我们自己的项目中写:
    # drf的配置,统一写成它
    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES': [
            'rest_framework.parsers.JSONParser',
            # 'rest_framework.parsers.FormParser',
            # 'rest_framework.parsers.MultiPartParser'
        ],
    }
    
    ps:限制的编码是在:from rest_framework import settings中找到的
    	
3.如果全局配置了只支持json,局部想支持3个怎么办
	解决:只需要在局部,视图类中写三个即可
    class BookView(APIView):
        parser_classes = [JSONParser, FormParser,MultiPartParser]
				pass
      
4.总结:能够处理的请求方式编码
		-优先从视图类中找
    -再去项目配置文件找
    -再去drf默认的配置中找

drf之响应

响应类的对象Response

from rest_framework.response import Response

构造方式

1.return Response({code:100})
Response(data, status=None, template_name=None, headers=None, content_type=None)
		data数据不要是render处理之后的数据,只需传递python的内建类型数据即可,REST framework会使用renderer渲染器处理data。
		data不能是复杂结构的数据,如Django的模型类对象,对于这样的数据我们可以使用Serializer序列化器序列化处理后(转为了Python字典类型)再传递给data参数。

2.参数说明:
    1.data: 响应提的内容,可以是字符串、字典、列表;
    2.status: http响应状态码,默认200# drf把所有响应码都定义成了一个常量
    3.template_name: 模板名称,用浏览器访问,看到好看的页面,而用postman访问,返回正常数据;   ps:网页打开,需要在应用里注册:rest_framework
    4.headers: 用于存放响应头信息的字典;
    	ps:响应头加数据-->headers={'name':'nana'}
    5.content_type: 响应编码,一般不用。响应数据的Content-Type,通常此参数无需传递,REST framework会根据前端所需类型数据来设置该参数。
    
    ps:data,status,headers

状态码

为了方便设置状态码,REST framewrok在rest_framework.status模块中提供了常用状态码常量。

1.信息告知 - 1xx

HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS

2.成功 - 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

3.)重定向 - 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

4.客户端错误 - 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

5.服务器错误 - 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

响应格式

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

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

3.默认的响应格式有两种:纯json、浏览器看到的样子

4.响应格式的限制方式
	1.限制方式一:在视图类中写,但只是局部有效
    from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
    
class BookView(APIView): 
    renderer_classes = [BrowsableAPIRenderer]
        def get(self,request):
          pass
        ...
  
	2.限制方式二:在配置文件中写--->全局有效    
    在我们自己的项目中写:
    # drf的配置,统一写成它
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
     'rest_framework.renderers.JSONRenderer',  # json渲染器
      'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览API渲染器
    )
}
    
    ps:限制的编码是在:from rest_framework import settings中找到的

5.全局配置了只支持json,局部想支持2个
	解决:只需要在局部,视图类中,写2个即可
	from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
    class BookView(APIView):
        renderer_classes = [JSONRenderer,BrowsableAPIRenderer]



常用属性

1.data
  传给response对象的序列化后,但尚未render处理的数据

2.status_code
状态码的数字

3.content
经过render处理后的响应数据


视图之两个视图基类

1.APIView:是REST framework提供的所有视图的基类,继承自Django的View父类。
		APIView:drf最顶层的视图类,继承了原生djagno的View
    	1 去除了csrf
      2 包装了新的request
      3 在执行视图类的方法之前,执行了三大认证
      4 处理了全局异常
        
2.GenericAPIView:GenericAPIView继承了APIView

GenericAPIView

使用APIView+序列化类+Response写接口

from .serializer import BookSerialzier
from rest_framework.response import Response
from .models import Book

class BookView(APIView):
    def get(self, request):
        qs = Book.objects.all()
        ser = BookSerialzier(qs, many=True)
        return Response({'code': 100, 'msg': '成功', 'results': ser.data})

    def post(self, request):
        ser = BookSerialzier(data=request.data)
        print(ser)
        if ser.is_valid():
            print(ser.validated_data)
            ser.save()

            return Response({'code': 100, 'msg': '成功'})
        else:

            return Response({'code': 100, 'msg': ser.errors})


class BookDetailView(APIView):
    def get(self, request, pk):
        book = Book.objects.all().get(pk=pk)
        ser = BookSerialzier(book)
        return Response({'code': 100, 'msg': '成功', 'results': ser.data})

    def put(self, request, pk):
        book = Book.objects.get(pk=pk)
        ser = BookSerialzier(data=request.data, instance=book)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '更新成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})

使用GenericAPIView+序列化类+Response写接口

# GenericAPIView伪代码
 class GenericAPIView(APIView):
     queryset = None
     serializer_class = None
     def get_queryset(self):
         return self.queryset
     def get_serializer(self):
         return self.serializer_class
     def get_object(self):
         return self.get_queryset().filter(pk=pk)
from rest_framework.generics import GenericAPIView
class BookView(GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerialzier

    def get(self, request):
        qs = self.get_queryset()
        ser = self.get_serializer(qs, many=True)
        return Response({'code': 100, 'msg': '成功', 'results': ser.data})

    def post(self, request):
        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '成功'})
        else:
            print(ser.errors)
            return Response({'code': 1001, 'msg': ser.errors})


class BookDetailView(GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerialzier
    def get(self, request, pk):
        book = self.get_object()
        ser = self.get_serializer(book)
        return Response({'code': 100, 'msg': '成功', 'results': ser.data})

    def put(self, request, pk):
        book = self.get_object()
        ser = self.get_serializer(data=request.data,instance = book)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '更新成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})

类属性方法

类属性

1.queryset:要序列化的所有数据
2.serializer_class:序列化类
3.lookup_field = 'pk' :查询单条时的key值
4.filter_backends:过滤类
5.pagination_class:分页类

类方法

1.get_queryset():获取所有要序列化的数据【后期可以重写】
2.get_serializer  : 返回序列化类【后期可以重写】
3.get_object :获取单个对象

总结

1.以后继承GenericAPIView写接口
		1.必须配置类属性
    	queryset
      serializer_class
		2.想获取要序列化的所有数据
    	get_queryset()
		3.想使用序列化类:
    	get_serializer
		4.想拿单条
    	get_object

作业

1.原生django想往响应头加数据,如何加?

1.在视图函数或者中间件中创建一个HttpResponse对象,或者使用现有的HttpResponse对象。
2.使用HttpResponse对象的['key']属性,将需要添加的响应头的键和值作为字典项添加进去。
3.以下是一个示例代码,展示如何在Django中往响应头添加数据:

    from django.http import HttpResponse
    def my_view(request):
        response = HttpResponse()
        response['X-Custom-Header'] = 'Custom Value'
        return response

2.编写一个post接口,只能接受json编码格式,响应json格式,响应头中加入:Access-Control-Allow-Origin = "*"

from rest_framework.views import APIView

from .serializer import BookSerialzier
from rest_framework.response import Response
from .models import Book
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer

class BookView(APIView):
    parser_classes = [JSONParser]
    renderer_classes = [JSONRenderer]
    def post(self, request):
        ser = BookSerialzier(data=request.data)
        print(ser)
        if ser.is_valid():
            print(ser.validated_data)
            ser.save()
            return Response({'code': 100, 'msg': '成功'},headers={'Access-Control-Allow-Origin':'*'})
        else:

            return Response({'code': 100, 'msg': ser.errors})

3、基于GenericAPIView编写图书5个接口,带出版社和作者

from django.shortcuts import render

# Create your views here.
from rest_framework.generics import GenericAPIView
from .models import Book
from .serializer import BookSerializer
from rest_framework.response import Response


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

    def get(self,request):
        qs = self.get_queryset()
        ser  = self.get_serializer(qs,many = True)
        return Response({'code':100,'msg':'查询成功','data':ser.data})

    def post(self,request):
        ser = self.get_serializer(data = request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '添加成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})


class BookDetail(GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    def get(self,request,pk):
        qs = self.get_object()
        ser = self.get_serializer(qs)
        return Response({'code': 100, 'msg': '查询成功', 'data': ser.data})

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

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

from rest_framework import serializers

from .models import Book
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['name','price','publish_name','author_list','authors','publish']
        extra_kwargs = {
            'authors':{'write_only':True},
            'publish':{'write_only':True}
        }

    publish_name = serializers.SerializerMethodField(read_only=True)
    author_list = serializers.ListField(read_only=True)

    def get_publish_name(self,obj):
        return obj.publish.name

4.封装5个类:ListModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin,

class ListModelMixin(GenericAPIView):

    def list(self):
        qs = self.get_queryset()
        ser = self.get_serializer(qs, many=True)
        return Response({'code': 100, 'msg': '查询成功', 'data': ser.data})

class CreateModelMixin(GenericAPIView):
    def create(self,request):
        ser = self.get_serializer(data = request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '添加成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})

class UpdateModelMixin(GenericAPIView):
    def update(self,request):
        qs = self.get_object()
        ser = self.get_serializer(data=request.data, instance=qs)

        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '修改成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})

class RetrieveModelMixin(GenericAPIView):

    def retrieve(self):
        qs = self.get_object()  #
        print(qs)
        ser = self.get_serializer(qs)
        print(ser)
        return Response({'code': 100, 'msg': '查询成功', 'data': ser.data})

class DestroyModelMixin(GenericAPIView):
    def destroy(self):
        self.get_object().delete()
        return Response({'code': 100, 'msg': '删除成功'})


# Create your views here.
from rest_framework.generics import GenericAPIView
from .models import Book
from .serializer import BookSerializer
from rest_framework.response import Response

class BookView(ListModelMixin,CreateModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

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

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

class BookDetail(UpdateModelMixin,RetrieveModelMixin,DestroyModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    def get(self,request,pk):
        return self.retrieve()

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

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

别人写的

from rest_framework.generics import GenericAPIView
from .models import Book
from .serializer import BookSerializer
from rest_framework.mixins import RetrieveModelMixin,ListModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin

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

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



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

class BookDetail(GenericAPIView,UpdateModelMixin,RetrieveModelMixin,DestroyModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    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)

4.基于DRF的Response,封装一个自己的Response,使它更符合我们规范{code:100,msg:成功,data:...}

from rest_framework.generics import GenericAPIView
from .models import Book
from .serializer import BookSerializer

# from rest_framework.response import Response
from rest_framework.response import Response as DrfResponse
class Response(DrfResponse):
    # def __init__(self, code = 100,msg=None,data = None):
    def __init__(self, data: dict, status=None, template_name=None, headers=None, content_type=None):
        if data.get("code") is None:
            data["code"] = 100
        if data.get("msg") is None:
            data["msg"] = "请求成功"
        super().__init__(data, status, template_name, headers, content_type)

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

    def get(self,request):
        qs = self.get_queryset()
        ser  = self.get_serializer(qs,many = True)
        return Response({
                    "msg": '查询成功',
                    "data": ser.data
                })

    def post(self,request):
        ser = self.get_serializer(data = request.data)
        if ser.is_valid():
            ser.save()
            return Response({
                    "msg": '添加成功'
                })
        else:
            return Response({'msg': ser.errors})

class BookDetail(GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    def get(self,request,pk):
        qs = self.get_object()
        ser = self.get_serializer(qs)
        # self.lookup_field
        return Response({'msg': '查询成功', 'data': ser.data})
    def put(self,request,pk):
        qs  = self.get_object()
        ser = self.get_serializer(data = request.data,instance = qs)
        if ser.is_valid():
            ser.save()
            return Response({'msg': '修改成功'})
        else:
            return Response({'code':1001,'msg': ser.errors})

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

5.自己封装出9个视图子类,能方便实现5个接口中某一个或多个

class ListModelMixin(GenericAPIView):

    def list(self):
        qs = self.get_queryset()
        ser = self.get_serializer(qs, many=True)
        return Response({'code': 100, 'msg': '查询成功', 'data': ser.data})

class CreateModelMixin(GenericAPIView):
    def create(self,request):
        ser = self.get_serializer(data = request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '添加成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})

class UpdateModelMixin(GenericAPIView):
    def update(self,request):
        qs = self.get_object()
        ser = self.get_serializer(data=request.data, instance=qs)

        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '修改成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})


class RetrieveModelMixin(GenericAPIView):

    def retrieve(self):
        qs = self.get_object()  #
        print(qs)
        ser = self.get_serializer(qs)
        print(ser)
        return Response({'code': 100, 'msg': '查询成功', 'data': ser.data})


class DestroyModelMixin(GenericAPIView):
    def destroy(self):
        self.get_object().delete()
        return Response({'code': 100, 'msg': '删除成功'})


from rest_framework.generics import GenericAPIView
class ListAPIView(ListModelMixin):
    def get(self,request):
        return self.list()

class CreateAPIView(CreateModelMixin):
    def post(self, request):
        return self.create(request)


class RetrieveAPIView(RetrieveModelMixin):

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

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

class DestroyAPIView(DestroyModelMixin):
    def delete(self,request,pk):
        return self.destroy()

class ListCreateAPIView(ListModelMixin,CreateModelMixin):
    def get(self,request):
        return self.list()
    def post(self,request):
        return self.create(request)

class RetrieveUpdateDestroyAPIView(RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    def get(self,request,pk):
        return self.retrieve()
    def put(self,request,pk):
        return self.update(request)
    def delete(self,request,pk):
        return self.destroy()

class RetrieveDestroyAPIView(RetrieveModelMixin,DestroyModelMixin):
    def get(self,request,pk):
        return self.retrieve()
    def delete(self,request,pk):
        return self.destroy()


class RetrieveUpdateAPIView(RetrieveModelMixin,UpdateModelMixin):
    def get(self,request,pk):
        return self.retrieve()
    def put(self,request,pk):
        return self.update(request)


from django.shortcuts import render

from .models import Book
from .serializer import BookSerializer
from rest_framework.response import Response

class BookView(ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

class BookDetail(RetrieveUpdateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

6 、封装一个视图类,实现某个表的5个接口,使用方式如下(这个比较难)

class ListModelMixin(GenericAPIView):
    def list(self):
        qs = self.get_queryset()
        ser = self.get_serializer(qs, many=True)
        return Response({'code': 100, 'msg': '查询成功', 'data': ser.data})

class CreateModelMixin(GenericAPIView):
    def create(self,request):
        ser = self.get_serializer(data = request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '添加成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})

class UpdateModelMixin(GenericAPIView):
    def update(self,request):
        qs = self.get_object()
        ser = self.get_serializer(data=request.data, instance=qs)

        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '修改成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})


class RetrieveModelMixin(GenericAPIView):

    def retrieve(self):
        qs = self.get_object()  #
        print(qs)
        ser = self.get_serializer(qs)
        print(ser)
        return Response({'code': 100, 'msg': '查询成功', 'data': ser.data})


class DestroyModelMixin(GenericAPIView):
    def destroy(self):
        self.get_object().delete()
        return Response({'code': 100, 'msg': '删除成功'})


class ListCreateAPIView(ListModelMixin,CreateModelMixin):
    def get(self,request):
        return self.list()
    def post(self,request):
        return self.create(request)


class RetrieveUpdateDestroyAPIView(RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    def get(self,request,pk):
        return self.retrieve()
    def put(self,request,pk):
        return self.update(request)
    def delete(self,request,pk):
        return self.destroy()


class ModelViewSet(ListCreateAPIView,RetrieveUpdateDestroyAPIView):
        def get(self,request,**kwargs):
            if not kwargs:
                return self.list()
            else:
                print(11)
                return self.retrieve()

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

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

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

class BookView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
from django.contrib import admin
from django.urls import path,include
from .views import BookView

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/<int:pk>/',BookView.as_view() ),
path('books/',BookView.as_view() )]

7.研究importlib,如何动态导入模块

1.在Python中,你可以使用importlib模块来实现动态导入模块。importlib提供了一组函数,可以在运行时动态导入模块,而不是在代码的开头进行静态导入。

2.下面是使用importlib动态导入模块的一般步骤:
    2.1. 首先,你需要导入importlib模块:
      import importlib
    2.2. 接下来,可以使用import_module()函数来动态导入模块。该函数接受模块的名称作为参数,并返回一个表示该模块的对象。你可以将该对象分配给一个变量,以便在后续的代码中使用该模块:
      module_name = 'my_module'  # 模块的名称
      module = importlib.import_module(module_name)
    3.3.可以使用module变量来访问被导入模块中的函数、变量或类:
      module.some_function()
      module.some_variable
    ps:1.import_module()函数可以接受一个完整的模块名称,例如'my_package.my_module',也可以只接受模块名称的一部分。如果你只提供了模块的一部分名称,那么Python将在导入过程中根据当前的搜索路径查找匹配的模块。

       2.如果你需要重新加载已经导入的模块,可以使用reload()函数:
        importlib.reload(module)
        reload()函数会重新加载指定的模块,并返回重新加载后的模块对象。