day84

1 修改,删除接口
2 高级用法之source
3 模型类序列化器
4 高级用法之SerializerMethodField
5 drf的请求与相应
6 通过配置,选择默认模板的显示形式(浏览器方式,json方式)
7 many=True源码分析,局部全局钩子源码解析

## 1 修改,删除接口

### views.py

```python
    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

```python
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

```python
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 模型类序列化器

```python
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  # 了解,跨表1查询,最多建议写3
        # 重写某些字段
        publish = serializers.CharField(max_length=32,source='publish.name')
        # 局部钩子,全局钩子,跟原来完全一样
3 新增,修改
    -统统不用重写create和update方法了,在ModelSerializer中重写了create和update
```



## 4 高级用法之SerializerMethodField

```python
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


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的请求与相应

```python
# 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__
# 自己封装一个response,继承drf的Response




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





## 7 many=True源码分析,局部全局钩子源码解析

```python
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
```

views.py

from django.shortcuts import render

# Create your views here.

from rest_framework.response import Response
from rest_framework.views import APIView
from app01 import serrializer
from app01 import models


class MyView(APIView):
    def get(self, request):
        return Response({'name': 'abc', 'age': 1111})


class Index(APIView):
    def get(self, request, *args, **kwargs):
        # 这个request是新的drf的Request类的对象
        print(type(request))
        print(type(request._request))
        print(request._request.method)
        print(request.method)
        print(request.POST)

        print(request.data)
        return Response({'name': 'sss'})


# class Book(APIView):
#     def get(self, request, *args, **kwargs):
#         dic = models.Book.objects.all()
#         ser = serrializer.BookSerializer(instance=dic, many=True)  # 实例化需要传入对象,如果是多条则many=True
#         print(type(ser))  # # rest_framework.serializers.ListSerializer
#         return Response(ser.data)
#
#     def post(self, request):
#         # post提交的数据都在request.data中  是个字典
#         ser = serrializer.BookSerializer(data=request.data)  # post请求需要传入data
#         if ser.is_valid():  # 校验
#             ser.save()  # 保存至数据库
#             return Response(request.data)
#         else:
#             return Response(ser.errors)
#
#
# class BookDetail(APIView):
#     def get(self, request, id):
#         book = models.Book.objects.filter(id=id).first()
#         ser = serrializer.BookSerializer(instance=book)  # 单个数据不能many=True
#         print(type(ser))  # app01.serializer.BookSerializer
#         return Response(ser.data)
#
#     def put(self, request, id):  # 修改
#         dic = {'code': 100, 'msg': ''}
#         book = models.Book.objects.filter(id=id).first()
#         try:
#             ser = serrializer.BookSerializer(instance=book, data=request.data)
#             ser.is_valid(raise_exception=True)  # 省去if判断,添加raise_exception=True,若校验通过则继续执行否则抛出异常
#             ser.save()
#             dic['msg'] = '修改成功'
#             dic['result'] = ser.data
#         except Exception as e:
#             print(e)
#             dic['code'] = 101
#             dic['msg'] = '未知异常'
#         return Response(dic)
#
#     def delete(self, request, id):
#         dic = {'code': 100, 'msg': '删除成功'}
#         models.Book.objects.filter(id=id).delete()
#         return Response(dic)


class Book(APIView):
    def get(self, request, *args, **kwargs):
        dic = models.Book.objects.all()
        ser = serrializer.BookModelSerializer(instance=dic, many=True)  # 实例化需要传入对象,如果是多条则many=True
        print(type(ser))  # # rest_framework.serializers.ListSerializer
        return Response(ser.data)

    def post(self, request):
        # post提交的数据都在request.data中  是个字典
        ser = serrializer.BookModelSerializer(data=request.data)  # post请求需要传入data
        if ser.is_valid():  # 校验
            ser.save()  # 保存至数据库
            return Response(ser.data)
        else:
            return Response(ser.errors)


from  rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
class BookDetail(APIView):
    renderer_classes = [JSONRenderer]       # 局部配置
    def get(self, request, id):
        book = models.Book.objects.filter(id=id).first()
        ser = serrializer.BookModelSerializer(instance=book)  # 单个数据不能many=True
        print(type(ser))  # app01.serializer.BookSerializer
        return Response(ser.data)

    def put(self, request, id):  # 修改
        dic = {'code': 100, 'msg': ''}
        book = models.Book.objects.filter(id=id).first()
        try:
            ser = serrializer.BookModelSerializer(instance=book, data=request.data)
            ser.is_valid(raise_exception=True)  # 省去if判断,添加raise_exception=True,若校验通过则继续执行否则抛出异常
            ser.save()
            dic['msg'] = '修改成功'
            dic['result'] = ser.data
        except Exception as e:
            print(e)
            dic['code'] = 101
            dic['msg'] = '未知异常'
        return Response(dic)

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

models.py

from django.db import models


# Create your models here.
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):
        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

serializer.py

from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from app01 import models


def check_publish(data):
    if len(data) > 10:
        raise ValidationError('最长不能超过10')
    else:
        return data


class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    name = serializers.CharField(max_length=32, source='title')  # source指定该字段对应表中的哪一个字段,并且不能同名
    price = serializers.DecimalField(max_digits=5, decimal_places=2, read_only=True)
    # publish = serializers.CharField(max_length=32, validators=[check_publish, ],
    #                                 required=False)  # validators验证,列表中写函数内存地址
    # func_test = serializers.CharField(source='test')  # 执行表模型中的test方法,并将返回值赋给该字段
    publish_addr = serializers.CharField(source='publish.addr')  # source支持跨表操作

    publish = serializers.SerializerMethodField()   # SerializerMethodField跨表查询,需要搭配写一个 'get_字段名' 方法
    def get_publish(self,obj):
        dic = {'name':obj.publish.name, 'addr':obj.publish.addr}
        return dic

    # 因为没有建立表关联关系,不知道要存哪一张表,所以需要手动重写create
    def create(self, validated_data):
        res = models.Book.objects.create(**validated_data)
        print(res)
        return res

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

    # 局部钩子
    def validate_title(self, data):
        if data.startswith('sb'):
            raise ValidationError('不能以sb开始')
        else:
            return data

    # 全局钩子
    def validate(self, attrs):
        title = attrs.get('title')
        publish = attrs.get('publish')
        if title == publish:
            raise ValidationError('重名!')
        else:
            return attrs


# class BookModelSerializer(serializers.ModelSerializer):
#     # publish = serializers.CharField(max_length=32, source='publish.name')   # 重写publish字段,通过source跨表操作
#
#     class Meta:
#         model = models.Book  # 表示该序列化类与book表建立了关系
#         # fields = ['id', 'title', 'publish']  # fields中是序列化和反序列化的字段
#         fields = '__all__'  # 表示序列化所有字段(包括重写字段)
#         # exclude = ['id']        # 表示序列化除去列表中以外的所有字段   ### 不能与fields同时使用
#         # read_only_fields = ['price', 'publish']  # 序列化显示的字段
#         # write_only_fields = ['title']  # 反序列化需要传入的字段  (可能部分版本不能使用)
#
#         # extra_kwargs给指定字段添加额外参数
#         # extra_kwargs = {'title': {'max_length': 32, 'write_only': True}, 'publish': {'validators': [check_publish, ]}}
#         # depth = 1       # 表示可以跨1个表查询(连表一次)


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

    # publish = serializers.SerializerMethodField()  # SerializerMethodField跨表查询,需要搭配写一个 'get_字段名' 方法
    # def get_publish(self, obj):
    #     dic = {'name': obj.publish.name, 'addr': obj.publish.addr}
    #     return dic

 

posted @ 2020-11-05 22:14  板鸭没有腿  阅读(108)  评论(0)    收藏  举报