day84 序列化器的高级用法

昨日回顾

1 restful规范

只是一个规范,规范了前后端交互接口(api接口)格式

10条规范

- http部署

- 请求地址中有接口标识

  -https://api.baidu.com

  -https://www.baidu.com/api/

- 多版本共存

  -https://www.baidu.com/api/v1

  -https://www.baidu.com/api/v2

- 请求资源名词表示,可以复数

  -一切皆资源
  -https://www.baidu.com/api/v1/books/

- 请求方式表示操作资源的方式

  ​	-get:获取资源
  ​	-post:新增资源
  ​ -put:修改
  ​ -patch:修改
  ​ -delete:删除资源

-响应中带状态码
  -{code:100}
    
-响应中带错误信息
   -{code:100,msg:'错误'}
    
-响应中带链接地址

-响应数据遵循以下格式
    -多条数据  []
    -单条      {}
    -新增      新增的数据返回
    -修改      修改的数据返回
    -删除      空文档
    
-请求中带过滤条件 

2 序列化器

-把对象----》序列化器---》字典-----》Response--->json格式字符串给前端

-把前端传过来的数据---Request-》字典---》序列化器----》对象---》保存
-数据校验

-如何使用
    	-写一个序列化类 继承Serializer
        -在类中写字段
        	-字段类型:CharField...
            -字段属性参数:required...
        -在视图类中使用
        	-实例化得到对象
            	-序列化(对象--》字典)ser=XXSerialier(instance=对象,many=True)----》ser.data
                -反序列化(新增)(字典---》对象)ser=XXSerialier(data=字典)
                
  
-反序列化的校验(三种方式)

		-字段自己的校验
    
    	-validators=[函数内存地址,]
        
        -局部和全局钩子
        	-validate_字段名(self,data)
            -validate(self,attrs)
                
-wirte_only和read_only	

今日内容

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

2.1 修改返回到前端的字段名

​ source=title(title对应models里的title字段) ,在这里重新命名为name,这样返回到前端的字段名就为name

​ 注意:返回到前端字段名就不能再叫title了,这里是name

name = serializers.CharField(max_length=32,min_length=2,source='title')

2.2 如果表模型中有方法

# 执行表模型中的test方法,并且把返回值赋值给xxx
	xxx=serializers.CharField(source='test')

models.py

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32,null=True)
    price = models.DecimalField(max_digits=5, decimal_places=2,null=True)
    # publish = models.CharField(max_length=32)
    publish = models.ForeignKey(to='Publish',null=True,on_delete=models.CASCADE)

    def test(self):
        # python是强类型语言,不支持字符串和数字直接相加
        return self.title+str(self.price)
    
class Publish(models.Model):
    name=models.CharField(max_length=32)
    addr=models.CharField(max_length=32)
    def __str__(self):
        return self.name

2.3 source支持跨表操作

addr=serializers.CharField(source='publish.addr')
    
# 希望你们去看以下源码,内部如何实现的

3 模型类序列化器

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

ModelSerializer与常规的Serializer相同,但提供了:

  • 基于模型类自动生成一系列字段
  • 基于模型类自动为Serializer生成validators,比如unique_together
  • 包含默认的create()和update()的实现

3.1 定义

比如我们创建一个BookModelSerializer类

class BookModelSerializer(serializers.ModelSerializer):
    """图书数据序列化器"""
    class Meta:
        model = BookInfo
        fields = '__all__'
  • model 指明参照哪个模型类

  • fields 指明为模型类的哪些字段生成

  • 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 – 了解,跨表1查询,最多建议写3

3.2 指定字段

  1. 使用fields来明确字段,__all__表名包含所有字段,也可以写明具体哪些字段,如
class BookModelSerializer(serializers.ModelSerializer):
    publish=serializers.CharField(max_length=32,source='publish.name')
    addr=serializers.CharField(max_length=32,source='publish.addr')
    class Meta:
        model=models.Book # 该序列化类跟Book表建立了关系
        fields=['id','title','publish','addr'] # 序列化book表中的id,title,publish和addr字段
       # fields='__all__'
  1. 使用exclude可以明确排除掉哪些字段
class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model=models.Book # 该序列化类跟Book表建立了关系
        exclude=['publish']
  1. 显示指明字段,如:
class BookModelSerializer(serializers.ModelSerializer):
    # 重写某些字段
    publish=serializers.CharField(max_length=32,source='publish.name')
    addr=serializers.CharField(max_length=32,source='publish.addr')
    class Meta:
        model=models.Book # 该序列化类跟Book表建立了关系
        fields=['id','title','publish','addr'] # 序列化book表中的id,title,publish和addr字段
  1. 指明只读字段

可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model=models.Book # 该序列化类跟Book表建立了关系
        fields=['id','title','price','publish']
        read_only_fields=['price'] # 序列化显示的字段
        write_only_fields=['title']# 反序列化需要传入的字段

3.3 添加额外参数选项

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

extra_kwargs ={'title':{'max_length':32},'price':{'validators':[check,]}}
extra_kwargs ={'title':{'max_length':32,'write_only':True}}

注意:

新增,时改是统统不用重写create和update方法了,在ModelSerializer中重写了create和update

局部钩子,全局钩子,跟原来完全一样

了解:

class BookModelSerializer(serializers.ModelSerializer):
    # publish = serializers.CharField(max_length=32, source='publish.name')
    class Meta:
        model = models.Book
        fields = '__all__'
        # depth=1  # 跨表1查询,个人建议最多不要超过3,尽量不要用

4 高级用法之SerializerMethodField

例:取出图书的出版社详细信息(id,name,addr)

#方法一
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, 'id': obj.publish.id}
        return dic

#方法二
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:响应的编码方式,了解

6 自己封装一个Response对象

views.py

from app01.utils import CommonResponde
from rest_framework.status import HTTP_201_CREATED
from  rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer

class BookDetail(APIView):
    # renderer_classes = [BrowsableAPIRenderer, ]
    def get(self,request,id):
        res=models.Book.objects.all().filter(id=id).first()
        ser=BookSerializer(instance=res)
        return Response(ser.data)
    def put(self,request,id):
        res=CommonResponde()
        try:
            book=models.Book.objects.get(id=id)
            ser=BookModelSerializer(instance=book,data=request.data)
            ser.is_valid(raise_exception=True)
            ser.save()
            res.msg='成功'
            res.code = 100
            res.result=['dfghjkll']

        except Exception as e:
            print(str(e))
            res.msg='未知错误'
            res.code=101

        return Response(data=res.get_dic,status=HTTP_201_CREATED)

serializer.py

class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model=models.Publish
        fields=['name','addr']


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

utils.py

class CommonResponde:
    def __init__(self):
        self.code=100
        self.msg=''

    @property
    def get_dic(self):
        return self.__dict__
 # 自己封装一个response,继承drf的Response

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

8 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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值