DRF-Django rest framework

1. 修改删除接口

views.py

# 修改    
    def put(self, request, id):
        # 通过id取到对象
        res = {'code': 100, 'msg': ''}
        try:
            book = models.Book.objects.get(id=id)
            ser = BookSerializer(instance=book, data=request.data)
            ser.is_valid(raise_exception=True)
            ser.save()
            res['msg'] = '修改成功'
            res['result'] = ser.data

        except Exception as e:
            res['code'] = 101
            res['msg'] = str(e)

        return Response(res)

# 删除    
    def delete(self,request,id):
        response = {'code': 100, 'msg': '删除成功'}
        models.Book.objects.filter(id=id).delete()
        return Response(response)

serializer.py

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    title = serializers.CharField(max_length=32,min_length=2)
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    publish = serializers.CharField(max_length=32)

    def create(self, validated_data):
        res=models.Book.objects.create(**validated_data)
        print(res)
        return res

    def update(self, book, validated_data):
        book.title=validated_data.get('title')
        book.price=validated_data.get('price')
        book.publish=validated_data.get('publish')
        book.save()
        return book

2. 高级用法之source

1. 修改返回到前端的字段名
	# source=title 字段名就不能再叫 title (不能重名)
	name = serializers.CharField(max_length=32,min_length=2,source='title')
    
2. 如果表模型中有方法
	# 执行表模型中的test方法,并且把返回值赋值给xxx
	xxx=serializers.CharField(source='test')
    
3. source支持跨表操作
	addr=serializers.CharField(source='publish.addr')
    
注意: 
    source 如果是字段,会显示字段,如果是方法,会执行方法,不用加括号

3. 模型类序列化器

1. 原来用的序列化器Serilizer跟表模型没有直接联系
   模型类序列化器ModelSerilizer跟表模型有对应关系

2. 使用介绍
	class BookModelSerializer(serializers.ModelSerializer):
        class Meta:
            model=表模型         # 跟哪个表模型建立关系
            fields=[字段,字段]   # 序列化的字段,反序列化的字段
            fields='__all__'    # 所有字段都序列化,反序列化
            exclude=[字段,字段]  # 排除哪些字段(不能跟fields同时使用)
            read_only_fields=['price','publish']  # 序列化显示的字段
			write_only_fields=['title']           # 反序列化需要传入的字段
            extra_kwargs ={'title':{'max_length':32,'write_only':True}}
            depth=1  # 深度控制,写几往里拿几层,层数越多,响应越慢,个人建议最多建议写3
        # 重写某些字段
        publish = serializers.CharField(max_length=32,source='publish.name')
        # 局部钩子,全局钩子,跟原来序列化器Serilizer完全一样
        
3. 新增 修改
	不用重写create和update方法了,在ModelSerializer中重写了create和update

4. 高级用法之SerializerMethodField

# 方式一 BookSerializer + SerializerMethodField
class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    name = serializers.CharField(max_length=32,min_length=2,source='title')
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    publish = serializers.SerializerMethodField()
    def get_publish(self,obj):
        dic={'name':obj.publish.name,'addr':obj.publish.addr}
        return dic

# 方式二 BookModelSerializer + SerializerMethodField 
class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = '__all__'
    publish = serializers.SerializerMethodField()
    def get_publish(self,obj):
        dic={'name':obj.publish.name,'addr':obj.publish.addr}
        return dic    
    
# 方式三 使用序列化类的嵌套
    class PublishSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Publish
            # fields = '__all__'
            fields = ['name','addr']

    class BookModelSerializer(serializers.ModelSerializer):
        publish = PublishSerializer()
        class Meta:
            model = models.Book
            fields = '__all__'

5. drf的请求与相应

# Request
	-data :前端以post请求提交的数据都在它中
    -FILES :前端提交的文件
    -query_params:就是原来的request.GET
    -重写了 __getattr__
    	-使用新的request.method其实取得就是原生request.method(通过反射实现)
        
# Response
	-from rest_framework.response import Response
    -data:响应的字典
    -status:http响应的状态码
    	-drf提供给你了所有的状态码,以及它的意思
        from rest_framework.status import HTTP_201_CREATED
    -template_name:模板名字(一般不动),了解
    -headers:响应头,字典
    -content_type:响应的编码方式,了解
        
# 自己封装一个Response对象
      class CommonResponse:
        def __init__(self):
            self.code=100
            self.msg=''
        @property
        def get_dic(self):
            return self.__dict__

# 通过配置,选择默认模板的显示形式(浏览器方式,json方式)
	-配置文件方式(全局)
        -如果没有配置,默认有浏览器和json
        -drf有默认配置文件
            from rest_framework.settings import DEFAULTS
            REST_FRAMEWORK = {
            'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
                'rest_framework.renderers.JSONRenderer',  # json渲染器
                'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览API渲染器
            )}
    -在视图类中配置(局部)
    	-粒度更小
        -class BookDetail(APIView):
    		renderer_classes=[JSONRenderer,]

6. many=True

many=True
	__init__ => 一路找到 BaseSerializer => __new__决定了生成的对象是谁
    
# 源码    
def __new__(cls, *args, **kwargs):
    # We override this method in order to automatically create
    # `ListSerializer` classes instead when `many=True` is set.
    
    # 传入的参数是many=True,执行cls.many_init(*args, **kwargs)
    if kwargs.pop('many', False):
        return cls.many_init(*args, **kwargs) # rest_framework.serializers.ListSerializer 
    return super().__new__(cls, *args, **kwargs) # app01.serializer.BookSerializer

7. 局部全局钩子源码解析

# 局部全局钩子源码解析
	入口是is_valid() 
    	=> BaseSerializer => is_valid 
        	=> self._validated_data 
            	=> self.run_validation(self.initial_data)
                	=> Serializer这个类的:self.run_validation
   
# 重写父类Field的run_validation方法
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
    ......

    def run_validation(self, data=empty):
        """
        We override the default `run_validation`, because the validation
        performed by validators and the `.validate()` method should
        be coerced into an error dictionary with a 'non_fields_error' key.
        """
        # 验证空值
        (is_empty_value, data) = self.validate_empty_values(data)
        # 是空值返回data
        if is_empty_value:
            return data
        # 局部字段的校验和局部钩子校验 返回OrderedDict()实例化对象
        value = self.to_internal_value(data)
        try:
            # 运行验证器
            self.run_validators(value)
            # 全局钩子的校验
            value = self.validate(value)  
            """
            这里的全局钩子如果我们需要使用的时候,需要重写,重写的时候一定要返回被拿出来验证的属性
            def validate(self, attrs):
            	return attrs
            """
        except (ValidationError, DjangoValidationError) as exc:
            raise ValidationError(detail=as_serializer_error(exc))
        return value