2020-12-14drf之接口和高级用法

昨日回顾

1、restful规范

-只是一个规范,规范了前后端交互的接口(api接口)格式
-10条
    -https部署(api与用户的通信协议)
    -请求地址中有接口标识
        -https://api.baidu.com
        -https://www.baidu.com/api/
    -多版本共存
        -https://www.baidu.com/api/v1/
    -请求资源名词表示,可以复数
        -一切皆资源
        -https://www.baidu.com/api/v1/books/
    -请求方式表示操作资源的方式
        -get:获取资源
        -post:新增资源
        -put:修改
        -patch:修改
        -delete:删除
    -响应中带状态码
        -{code:100}
    -响应中带错误信息
        -{code:100,mag:‘错误’}
    -响应中带链接地址
    -响应数据遵循一下格式
        -多条数据[]
        -单条数据{}
        -新增  新增的数据返回
        -修改  修改的数据返回
        -删除  空文档
    -请求中带过滤条件

2、序列化器

-序列化
    -把对象--》序列化器--》字典--》Response--》json格式字符串给前端
-反序列化
    -把前端传过来的数据--Request--》字典--》序列化器--》对象--》保存
    -数据校验
    -如何使用
        -写一个序列化类,继承Serializer
        -在类中写字段
            -字段类型:CharField。。。
            -字段属性参数:required。。。
        -在视图类中使用
            -实例化得到对象
                -序列化(对象--》字典)ser=XXSerializer(instance=对象,many=True)---》ser.data
                -反序列化(新增)(字典---》对象)ser=XXSerializer(data=字典)
    -反序列化的校验(三种方式)
        -字段自己的校验
        -Validators=[函数内存地址,]
        -局部和全局钩子
            -validate_字段名(self,data)
            -validate(self,attrs)
    -write_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

-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')

3、模型类序列化器

-1、原来用的Serializer跟表模型没有直接关系,模型类序列化器ModelSerializer,跟表模型有对应关系
-2、使用
class BookModelSerializer(serializers.ModelSerializer):
        class Meta:
            model=表模型  # 跟那个表模型建立关系
            fields=[字段,字段]  # 序列化字段,反序列化的字段,都是这里边的
            fields='__all__'  # 所有字段都序列化,反序列化
            exclude=[字段,字段]  # 排除哪些字段,(不能跟fields同时使用)
            read_only_fields=['price','publish']  # 序列化显示的字段
            write_only_fields=['title']  # 反序列化需要传入的字段
            #给字段额外添加参数,是反序列化的校验参数,应为用了fields,__all__,就没法控制字段的属性了
            extra_kwargs={'title':{'max_length':32,'write_only':True}}
            depth=1 # 了解,跨表1查询,显示详细信息,最多建议写3
            # 重写某些字段
            publish = serializers.CharField(max_length=32,source='publish.name')
            # 局部钩子,全局钩子,跟原来完全一样
-3、新增,修改
    -统统不用重写create和update方法了,在ModelSerializer中重写了create和update,Serializer里没有重写,你只要不写就给你报错,
    就是鸭子类型,来控制子类的方法。

4 高级用法之SerializerMethodField

取出图书的出版社详细信息(id,name,addr),也就是字典套字典

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()

    # 必须搭配这个方法,返回啥,publish就显示啥,要传个参数。
    def get_publish(self,obj):  # 要接收个对象,这个对象是book对象
        dic={'name':obj.publish.name,'addr':obj.publish.addr}
        return dic  # 可控性高,返回详细信息

# 还可以用在这里,用法一毛一样
class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model=models.Book
        fields='__all__'
    #注意位置,不能缩进去了
    publish = serializers.SerializerMethodField()

    # 必须搭配这个方法,返回啥,publish就显示啥,要传个参数。
    def get_publish(self, obj):  # 要接收个对象,这个对象是book对象
        dic = {'name': obj.publish.name, 'addr': obj.publish.addr}
        return dic

#序列化类的嵌套,可以取一个序列化类的筛选字段,然后写道另一个序列化类里
class PublishModelSerializer(serializers.ModelSerializer):
    class Meta:
        model=models.Publish
        # fields='__all__'
        fields=['name','addr']

class BookModelSerializer(serializers.ModelSerializer):
    # publish=PublishModelSerializer()  # 把关联表的那个序列化筛选的字段,放这里,就可以控制这个关联字段的详情显示
    class Meta:
        model=models.Book
        fields='__all__'

5 drf的请求与响应

Request

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

Response

REST framework提供了一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。
REST framework提供了Response渲染器,用来根据请求头中的Accept(接收数据类型声明)来自动转换响应数据到对应格式。如果前端请求中未进行Accept声明,
则会采用默认的方式处理响应数据,我们可以通过配置来修改默认的响应格式。
    -from rest_framework.response import Response
    -data:响应的字典
    -status:http响应的状态码,默认时200
        -drf提供给你了所有的状态码,以及它的意思
        from rest_framework.status import HTTP_201_CREATED
    -template_name:模板名字(一般不动),了解
    -headers:响应头,字典
    -content: 经过render处理后的响应数据
    -content_type:响应的编码方式,了解,通常该参数无需传递,rest framework会根据前端所需类型数据来设置该参数

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

#通过配置,选择默认模板的显示形式,(浏览器方式,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 BookDetali(APIView):
        renderer_classes=[JSONRenderer,]

7、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

你可能感兴趣的:(2020-12-14drf之接口和高级用法)