• 02 Django REST Framework 序列化


     01-创建序列化类

    # 方式一:
    publish_list = models.Publish.objects.all()
    # 导入序列化组件
    from django.core import serializers
    
    serializers.serialize("json", publish_list)
    # 方式二:
    # 为queryset和model对象做序列化
    
    
    class PublishSerializers(serializers.Serializer):
        # 添加做序列化的字段
        name = serializers.CharField()
        email = serializers.CharField()
    
    publish_list = models.Publish.objects.all()
    
    PublishSerializers(publish_list, many=True)
    
    PublishSerializers(model_obj)

     Response

    from rest_framework.response import Response
    # 序列化 一对多  多对多
    
    class BookSerializers(serializers.Serializer):
        # 添加做序列化的字段
        title = serializers.CharField()
        price = serializers.CharField()
        # 一对多
        publish = serializers.CharField(source="publish.name")
        
        # 多对多
        authors = serializers.SerializerMethodField()
        
        def get_authors(self, obj):
            temp = []
            for obj in obj.authors.all():
                temp.append(obj.name)

    02-ModelSerializer

    # 等同于上面的
    
    from rest_framework.views import APIView
    
    class BookModelSerializers(serializers.ModelSerializer):
        class Meta:
            model = Book  # 表名
            fields = "__all__"
    
    
    class BookView(APIView):
        def get(self, request):
            book_list = Book.objects.all()
            bs = BookModelSerializers(book_list, many=True)
    
            return Response(bs.data)
    
        def post(self):
            pass

    03-提交post请求

    class BookView(APIView):
        def get(self, request):
            '''
            获取书籍
            :param request:
            :return:
            '''
            book_list = Book.objects.all()
            bs = BookModelSerializers(book_list, many=True)
    
            return Response(bs.data)
    
        def post(self, request):
            '''
            添加书籍
            :return:
            '''
            # post请求的数据
            bs = BookModelSerializers(data=request.data)
            if bs.is_valid():
                bs.save()  # 调用的是create方法
                # 返回的是添加的数据
                return Response(bs.data)
            else:
                # 错误的数据
                return HttpResponse(bs.errors)

    04-重写save中create方法

    class BookModelSerializers(serializers.ModelSerializer):
        class Meta:
            model = Book  # 表名
            fields = "__all__"
    
        publish = serializers.CharField(source="publish.pk)
        # 针对一对多字段publish,会报错,所以重写create方法
        def create(self, validated_data):
            book = Book.objects.create(title=validated_data["title"], price = validated_data["price"], pub_date = validated_data["pub_date"])
            book.authors.add(*validated_data["authors"])
    
            return book

     05-自定义方法

    class UserInfoSerializer(serializers.ModelSerializer):
        type = serializers.CharField(source="get_user_type_display")
        group = serializers.CharField(source="group.title")
        rls = serializers.SerializerMethodField()
    
        def get_rls(self, row):
            # 获取用户所有的角色
            role_obj_list = row.roles.all()
            ret = []
            # 获取角色的id和名字
            # 以字典的键值对方式显示
            for item in role_obj_list:
                ret.append({"id": item.id, "title": item.title})
            return ret
    
        class Meta:
            model = models.UserInfo
            fields = ['id','username','password','type','group','rls']

    06-自动序列化连表(depth)

    class UserInfoSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.UserInfo
            #fields = "__all__"
            fields = ['id','username','password','group','roles']
            #表示连表的深度
            depth = 1

    07-生成url

    # urls.py
    
    urlpatterns = [
        re_path('(?P<version>[v1|v2]+)/group/(?P<pk>d+)/', GroupView.as_view(),name = 'gp')    #序列化生成url
    ]
    class UserInfoSerializer(serializers.ModelSerializer):
        # 获取url
        group = serializers.HyperlinkedIdentityField(view_name='gp',lookup_field='group_id',lookup_url_kwarg='pk')
        class Meta:
            model = models.UserInfo
            #fields = "__all__"
            fields = ['id','username','password','group','roles']
            #表示连表的深度
            depth = 0

    效果:

     08-自定义数据验证规则

    # 自定义验证规则
    class GroupValidation(object):
        def __init__(self,base):
            self.base = base
    
        def __call__(self, value):
            if not value.startswith(self.base):
                message = "标题必须以%s为开头"%self.base
                raise serializers.ValidationError(message)
    
    
    class UserGroupSerializer(serializers.Serializer):
        title = serializers.CharField(validators=[GroupValidation('以我开头'),])    
    
    class UserGroupView(APIView):
        def post(self,request,*args, **kwargs):
            ser = UserGroupSerializer(data=request.data)
            if ser.is_valid():
                print(ser.validated_data['title'])
            else:
                print(ser.errors)
    
            return HttpResponse("用户提交数据验证")

     09-序列化外键用嵌套的方法来实现

    示例:

    # 轮播图
    class GoodsImageSerializer(serializers.ModelSerializer):
        class Meta:
            model = GoodsImage
            fields = ("image",)
    
    # 商品列表页
    class GoodsSerializer(serializers.ModelSerializer):
        # 覆盖外键字段
        category = CategorySerializer()
        # images是数据库中设置的related_name="images",把轮播图嵌套进来
        images = GoodsImageSerializer(many=True)
        class Meta:
            model = Goods
            fields = '__all__'

     10-添加自定义字段 不在model字段内

    class ForgetPWDSerializers(serializers.ModelSerializer):
        re_password = serializers.CharField(write_only=True)
    
        class Meta:
            model = UserModel
            fields = ('username', 'password', 're_password')

    原理:create最后在返回response体的时候,传递的参数serializer.data,其实做的是一个序列化的工作,它会依据你在class Meta里面设置的fields,去做序列化,将里面所有字段进行序列化,这个时候就会报错!

    解决方法:write_only 设置这个属性为true,去确保create/update的时候这个字段被用到,序列化的时候,不被用到!

     11-

     12-获取choice的值

    # 指定 source="get_category_display"
    
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)

    13-设定不需要校验字段

    # required=False
    
    id = serializers.IntegerField(required=False)

    14-序列化字段与反序列化字段

    # 前端 传 w_category 字段,序列化用category,反序列化用 w_category
    
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
    w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
    read_only=True 序列化字段;
    write_only=True 反序列化字段;
    book_obj = {
            "title": "Alex的使用教程",
            "w_category": 1,
            "pub_time": "2018-10-09",
            "publisher_id": 1,
            "author_list": [1, 2]
        }
    
    
    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False)
        title = serializers.CharField(max_length=32, validators=[my_validate])
        CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
        category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
        w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
        pub_time = serializers.DateField()
    
        publisher = PublisherSerializer(read_only=True)
        publisher_id = serializers.IntegerField(write_only=True)
        author = AuthorSerializer(many=True, read_only=True)
        author_list = serializers.ListField(write_only=True)
    
        def create(self, validated_data):
            book = Book.objects.create(title=validated_data["title"], category=validated_data["w_category"],
                                    pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])
            book.author.add(*validated_data["author_list"])
            return book
    
        def update(self, instance, validated_data):
            instance.title = validated_data.get("title", instance.title)
            instance.category = validated_data.get("category", instance.category)
            instance.pub_time = validated_data.get("pub_time", instance.pub_time)
            instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
            if validated_data.get("author_list"):
                instance.author.set(validated_data["author_list"])
            instance.save()
            return instance
    
        def validate_title(self, value):
            if "python" not in value.lower():
                raise serializers.ValidationError("标题必须含有python")
            return value
    
        def validate(self, attrs):
            if attrs["w_category"] == 1 and attrs["publisher_id"] == 1:
                return attrs
            else:
                raise serializers.ValidationError("分类以及标题不符合要求")
    第一版
    class BookSerializer(serializers.ModelSerializer):
        category_display = serializers.SerializerMethodField(read_only=True)
        publisher_info = serializers.SerializerMethodField(read_only=True)
        authors = serializers.SerializerMethodField(read_only=True)
    
        def get_category_display(self, obj):
            return obj.get_category_display()
    
        def get_authors(self, obj):
            authors_query_set = obj.author.all()
            return [{"id": author_obj.id, "name": author_obj.name} for author_obj in authors_query_set]
    
        def get_publisher_info(self, obj):
            # obj 是我们序列化的每个Book对象
            publisher_obj = obj.publisher
            return {"id": publisher_obj.id, "title": publisher_obj.title}
    
        class Meta:
            model = Book
            # fields = ["id", "title", "pub_time"]
            fields = "__all__"
            # depth = 1
            extra_kwargs = {"category": {"write_only": True}, "publisher": {"write_only": True},
                            "author": {"write_only": True}}
    第二版ModelSerializer

    15-put允许部分更新字段:partial=True

    16-自定义校验方法 my_validate

    # 三种 校验数据的方式:
    1. 校验全部字段  
        validate
    
    2. 校验单个字段 如:title
        validate_title
    
    3. 自定义校验方法  
        my_validate
    
    def my_validate(value):
        if "敏感信息" in value.lower():
            raise serializers.ValidationError("不能含有敏感信息")
        else:
            return value

      my_validate的权重 高于 validate_title

    17-设置depth = 1,获取外键字段及多对多字段的值

    class BookSerializer(serializers.ModelSerializer):
        # 获取 category 字段的选择 的值,是数字对应的值,而不是数字
        category = serializers.CharField(source="get_category_display")
    
        class Meta:
            model = Book
            # fields = ["id", "title", "pub_time"]
            fields = "__all__"
            depth = 1

    18-SerializerMethodField 用于 外键字段 等,只获取想要的字段的值

    class BookSerializer(serializers.ModelSerializer): 
        category_display = serializers.SerializerMethodField(read_only=True)
        publisher_info = serializers.SerializerMethodField(read_only=True)
        authors = serializers.SerializerMethodField(read_only=True)
    
        def get_category_display(self, obj):
            return obj.get_category_display()
    
        def get_authors(self, obj):
            authors_query_set = obj.author.all()
            return [{"id": author_obj.id, "name": author_obj.name} for author_obj in authors_query_set]
    
        def get_publisher_info(self, obj):
            # obj 是我们序列化的每个Book对象
            publisher_obj = obj.publisher
            return {"id": publisher_obj.id, "title": publisher_obj.title}
    
        class Meta:
            model = Book
            # fields = ["id", "title", "pub_time"]
            fields = "__all__"
            # depth = 1
            extra_kwargs = {"category": {"write_only": True}, "publisher": {"write_only": True},
                            "author": {"write_only": True}}

     

  • 相关阅读:
    编程之美 2014资格赛 格格取数
    ios游戏开发--cocos2d学习(1)
    ios开发中常用的也是最基本的mysql语句
    无限树形结构的数据库表设计
    认真的辞职
    几种JavaScript富应用MVC MVVM框架
    javascript创建对象和属性的几种方式
    webresource.axd文件的配置及使用
    ITextSharp用来生成 PDF 的一个组件
    flexpaper 开源轻量级的在浏览器上显示各种文档的组件
  • 原文地址:https://www.cnblogs.com/pgxpython/p/9961944.html
Copyright © 2020-2023  润新知