Day 23 DRF序列化器高级用法及相关源码

Day 23 DRF序列化器高级用法及相关源码

一、修改删除接口

根据restful规范–资源操作由请求方式决定

所以目前我们需要不同不同的路由视图类来实现这个功能

1. 路由的配置

# urls.py

url(r'^book/$', views.Book.as_view()),  # get 所有的查询 以及增加
url(r'^book/(?P<id>\d+)$', views.BookInfo.as_view()),  # 单个的 删 改 查

2.CBV视图的编写

# views.py

class BookInfo(APIView):
    # 查询单本书的操作,与查询多本相同 都是拿到对象后,经过序列器返回
    def get(self, request, id):
        one_book = models.Book.objects.filter(id=id).first()
        if one_book:
            ser = serializer.BookSerializer(instance=one_book)
            return Response(ser.data)
        else:
            raise ValidationError('找不到这本书哦!')
    
    # 在这里我们就可以不用通过序列器了,直接返回操作信息就好了
    def delete(self, request, id):
        one_book = models.Book.objects.filter(id=id)
        if one_book:
            one_book.delete()
            return Response('删除成功!')
        else:
            raise ValidationError('找不到这本书哦!')
    # 这里需要经过序列器 步骤相同
    def patch(self, request, id):
        result = {'code': 100, 'msg': '修改成功!'}
        one_book = models.Book.objects.filter(pk=id)
        print(request.data)
        # 在实例化 对象的时候 我们也要将修改的数据 data 传进去,partial是否为单个 可以不加
        ser = serializer.BookSerializer(data=request.data, instance=one_book, partial=True)
        if ser.is_valid():
            ser.save() # 这里我们需要注意的是 要调用save方法  我们要在序列器中重写啊update
            return Response(result)  # 不能返回 ser.data会报错
        else:
            result['code'] = 101
            result['data'] = '该书不存在!'
            return Response(result)

3.序列器

def update(self, instance, validated_data):  # 会自动补全后面的参数
    instance.update(**validated_data)  # 直接赋值就可以了 
    print(instance)
    return instance  # 将结果返回

我们来用postman演示下

image-20201105153442931

(这里应该是第三条记录,取错了,但是结果是一样的!)

二、序列化器 高级用法之source

路由

    url(r'^book/', views.Book.as_view()),

模型

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    author = models.CharField(max_length=32)
    publish = models.CharField(max_length=32)
    
    def author_func(self):
        return '这是' + self.author + '写的'

序列化器

class Book(serializers.Serializer):
    name = serializers.CharField(max_length=32)
    price = serializers.CharField()
    author = serializers.CharField(min_length=1)
    publish = serializers.CharField()
    # 执行表模型中的 author_func方法,并把 返回值赋予  book_info
    # 注意 字段名不能和 表模型方法 相同
    book_info = serializers.CharField(source='author_func')

视图函数

class Book(APIView):
    
    def get(self,request, *args, **kwargs):
        books = models.Book.objects.all()
        ser = serializer.Book(instance=books, many=True)
        return Response(ser.data)

测试

image-20201105161756028

三、模型类序列化器

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

1.重写表结构

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    author = models.ManyToManyField(to='Author')
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)


class Publish(models.Model):
    name = models.CharField(max_length=32)
    address = models.CharField(max_length=64)


class Author(models.Model):
    name = models.CharField(max_length=32)
    salary = models.IntegerField()
    phone = models.CharField(max_length=11)

2.路由配置

url(r'^bookmodel/', views.BookModel.as_view()),

3.视图配置

class BookModel(APIView):
    
    def get(self, request, *args, **kwargs):
        books = models.Book.objects.all()
        ser = serializer.BookModel(instance=books, many=True)
        return Response(ser.data)

4.指定字段

4.1 使用fields来明确字段,__all__表名包含所有字段,也可以写明具体哪些字段,如
class BookModel(serializers.ModelSerializer):
    class Meta:
        model = models.Book  # 表模型 与之关联
        fields = ['name', 'author', 'publish']

image-20201105170522921

4.2 使用exclude可以明确排除掉哪些字段
class BookModel(serializers.ModelSerializer):
    class Meta:
        model = models.Book  # 表模型 与之关联
        exclude = ['author', 'publish']

image-20201105170834770

4.3 默认ModelSerializer使用主键作为关联字段,但是我们可以使用depth来简单的生成嵌套表示,depth应该是整数,表明嵌套的层级数量。如:
class BookModel(serializers.ModelSerializer):
    class Meta:
        model = models.Book  # 表模型 与之关联
        fields = '__all__'  # 查询所有
        depth = 1

image-20201105171154039

4.4 指明只读字段
class BookModel(serializers.ModelSerializer):
    class Meta:
        model = models.Book  # 表模型 与之关联
        fields = '__all__'
        read_only_fields = ['name', 'author', 'publish']

image-20201105191515313

4.5 只写字段

反序列化需要传入的字段

class BookModel(serializers.ModelSerializer):
    class Meta:
        model = models.Book  # 表模型 与之关联
        fields = '__all__'
        write_only_fields = ('name', 'author', 'publish')

image-20201105192115808

4.6 添加额外参数

我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数

class BookModel(serializers.ModelSerializer):
    class Meta:
        model = models.Book  # 表模型 与之关联
        fields = ['name', 'author', 'publish']
        depth = 1
        extra_kwargs = {'name': {'min_length': 2}}

image-20201105192955467

四、高级用法之SerializerMethodField

善用 SerializerMethodField 来优化不必要的查询

方案一

depth

方案二

其实在很多时候我们并不需要在查询 Book对象的时候查询所拥有的Author对象,很多时候我们只是需要一个 Book所拥有 Author对象的总数就可以了,如果有需要再去查询 Author列表详细。此时我们就可以使用 Django REST framework 提供的 SerializerMethodField 来实现这个目的

减少 depth 的使用

class BookModel(serializers.ModelSerializer):
    class Meta:
        model = models.Book  # 表模型 与之关联
        fields = '__all__'
    
    author = serializers.SerializerMethodField()
    # 名字不可以概念 实例化那个 就只能 get_字段名
    def get_author(self, obj):
        # name = obj.author.name  # 也可以单个返回
        dic = {'name':obj.author.name,'salary':obj.author.name}
        return dic

方案三

使用序列化类的嵌套

class Author(serializers.ModelSerializer):
    class Meta:
        # 关联
        model = models.Author
        # 选取需要显示的字段
        fields = ['name', 'salary']


class BookModel(serializers.ModelSerializer):
    # 要实例化哦
    # 也要和 book的字段对应
    author = Author()
   
    class Meta:
        model = models.Book  # 表模型 与之关联
        fields = '__all__'

image-20201105195723570

五、drf的请求与响应

1. Request

	-data :前端以post请求提交的数据都在它中
    -FILES :前端提交的文件
    -query_params:就是原来的request.GET
    -重写了 __getattr__
    	-使用新的request.method其实取得就是原生request.method(通过反射实现)

2. Response

	-from rest_framework.response import Response
    -data:响应的字典
    -status:http响应的状态码
    	-drf提供给你了所有的状态码,以及它的意思
        from rest_framework.status import HTTP_201_CREATED
    -template_name:模板名字(一般不动),了解
    -headers:响应头,字典
    -content_type:响应的编码方式,了解

3. 自己封装一个response,继承drf的Response

根据restful规范,要返回状态码和错误信息,但是不同的方法中就造成了大量的代码冗余,我们就可以自己写一个response,这样我们就可以直接通过 . 来调用了

    
 # 自己封装一个Response对象
      class CommonResponse:
        def __init__(self):
            self.code=100
            self.msg=''
        @property
        def get_dic(self):
            return self.__dict__

4. 通过配置,选择默认模板的显示形式(浏览器方式,json方式)

drf和django一样 有一个默认的settings,这里面包含了各种显示模式,我们可以在django的setting中改变这个配置

# 通过配置,选择默认模板的显示形式(浏览器方式,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,]

六、many=True源码分析,局部全局钩子源码解析

1 many=True
	-__init__----->一路找到了BaseSerializer---》__new__决定了生成的对象是谁
    
2 入口是is_valid()---》BaseSerializer--》is_valid---》self._validated_data = self.run_validation(self.initial_data)
	-Serializer这个类的:self.run_validation
def run_validation(self, data=empty):
        value = self.to_internal_value(data)  # 局部字段自己的校验和局部钩子校验
        try:
            self.run_validators(value)
            value = self.validate(value)  # 全局钩子的校验
        except (ValidationError, DjangoValidationError) as exc:
            raise ValidationError(detail=as_serializer_error(exc))
        return value

七、接口幂等性,是什么,如何弄?

接口幂等性,是什么,如何弄

八、接口

什么是接口 ?

接口只是定义了一些方法,而没有去实现,多用于程序设计时,只是设计需要有什么样的功能,但是并没有实现任何功能,这些功能需要被另一个类(B)继承后,由 类B去实现其中的某个功能或全部功能。

个人的理解,多用于协作开发时,有不同的人在不同的类中实现接口中的各个方法。

在python中接口由抽象类和抽象方法去实现,接口是不能被实例化的,只能被别的类继承去实现相应的功能。

个人觉得接口在python中并没有那么重要,因为如果要继承接口,需要把其中的每个方法全部实现,否则会报编译错误,还不如直接定义一个class,其中的方法实现全部为pass,让子类重写这些函数。

当然如果有强制要求,必须所有的实现类都必须按照接口中的定义写的话,就必须要用接口。

其实就是统一 子类 的行为

python有三种限制子类的方式

  • 抛异常限制
  • abc模块限制
  • 人为限制(鸭子类型)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值