REST framework(序列化器)

一、字段参数

字段的常见参数:    
    required=True 字段不能为空
    allow_null=True 字段允许为null
    allow_blank=True 数据校验阶段,字段可以为null
    write_only=True 字段只能写
    read_only=True 字段只能读
    source="related_name"  # 指定别名
    default="默认值"  指定字段默认值
    format="%Y-%m-%d %X"  设置时间格式
    error_messages={"max_length":"字段太长"}  指定错误信息

二、序列化器Serializer类

注:source 可以指定一个字段名,表模型,还可以指定表模型里的方法,source 指定的如果是方法不用加括号自己执行

  序列化器Serializer类:

1,写一个类继承serializers.Serializer
2,视图层调这个类实例化产生实例化对象
3,注意返回用的是rest_framework 的 Response


from rest_framework import serializers
class BookSerialize(serializers.Serializer):
    nid = serializers.CharField()

    #  (1)source的用法1:起别名
    # name = serializers.CharField(source="name")  # source 指定要序列化的字段,不能写两个name
    author_name = serializers.CharField(source="name")  # 相当于给name字段显示起别名为book_name
    price = serializers.CharField()

    #  (2)source的用法2:可以指定表模型
    # publish = serializers.CharField()  # 可以利用__str__ 显示序列化
    # publish = serializers.CharField(source="publish.name")  # source可以指定表模型

    #  (3)source的用法3:指定表模型的方法,相当于直接触发序列化表里的方法执行
    # xx = serializers.CharField(source="test")   # source可以指定表模型的方法,将该返回值的结果赋值给xx 相当于给表模型添加字段

    # rest_framework组件之SerializerMethodField 的方法使用,写一个get+字段名的函数
    authors = serializers.SerializerMethodField()
    def get_authors(self, obj):  # obj为序列化的对象
        author_list = obj.authors.all()
        ser = AuthorSerialize(author_list, many=True)
        return ser.data   # 返回的结果为序列化打印的对象

  视图:

视图层:
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.myserialize import BookSerialize
class Books(APIView):
    def get(self, request, *args, **kwargs):
        response = {"status": 100, "msg": "查看所有"}

        # 方式1:自己手撸序列化
        book_list = models.Book.objects.all()
        data = [{"title": book.title, "publish_date": book.publishDate} for book in book_list ]
        return HttpResponse("ok")

        # 方式2:django原生自带序列化  (不推荐使用)
        from django.cores.serializes import serialize
      books = models.Book.objects.all()
        data = serialize(books,'json')  # django自带的序列化组件
        return HttpResponse(data)

        # 方式3:推荐使用
        all_author = Author.objects.all()  # 产生序列化的对象
        ser = BookSerialize(all_author, many=True)    # many=True 表示序列化多条   many=False 表示序列化单条
        response["data"] = ser.data   # 序列化以后的数据在data里
        return Response(response)

        # 方式4:
        ret=models.Book.objects.all().values('nid','title')
    dd=list(ret)
        return HttpResponse(json.dumps(dd))

三、序列化器ModelSerializer类

  3.1 单层的序列化器:

  序列化器ModelSerializer类:

1,写一个类继承ModelSerializer
2,视图层调这个类实例化产生实例化对象
3,注意返回用的是rest_framework 的 Response

from rest_framework import serializers
class BookSerialize(serializers.ModelSerializer):   # ModelSerializer类下接元信息
    class Meta:
        model = models.Author
        # fields = ["name",]   # 指定序列化哪些字段
        fields = '__all__'  # 序列化所有字段 一般不用
        # exclude = ["name", ]  # 排除那些字段不显示,不与查询所有连用
        # depth=1  指定查询的深度

    publish=serializers.CharField(source='publish.name')   # 元信息连表显示的是字段id 所以重写序列化字段

  视图:

视图层:
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.myserialize import BookSerialize
class Books(APIView):
    def get(self, request, *args, **kwargs):
        response = {"status": 100, "msg": "查看所有"}

        all_author = Author.objects.all()  # 产生序列化的对象
        ser = BookSerialize(all_author, many=True)    # many=True 表示序列化多条
        response["data"] = ser.data   # 序列化以后的数据在data里

        return Response(response)

  3.2 层级序列化器:

调查表-->模板表-->问卷调查表-->问题选项表
# 问题选项
class SurveyChoiceSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.SurveyChoice
        fields = "__all__"


# 问卷调查问题表
class SurveyQuestionSerializer(serializers.ModelSerializer):
    # 层级序列化器方式三:
    # choices = serializers.SerializerMethodField()
    # 创建需要查询的字段函数:get+字段名
    # def get_choices(self, obj):
    #     # 反向查询:表名(小写)_set
    #     return list(obj.surveychoice_set.values()) # 基于对象的查找

    """"
    层级序列化器方式三总结:
    1.正向查询:当前表的字段名.需要查询的关联表的字段名
    2.反向查询:关联表(小写)_set.values()
    """
    """
    层级序列化器方式一总结:
    1.many参数:只有manytomany字段需要指定many=True
    2.source参数:
        正向查询:source="字段.关联表字段",当前字段可以取别名
        反向查询:models表中添加related_name参数:当前使用的子序列化器指定source=related_name(值)
        多条记录:source=字段.all
    """

    # 问卷问题选项
    choices = SurveyChoiceSerializer(many=True, source="answers")

    # 自定义value字段
    value = serializers.CharField(default="", error_messages={
        "invalid": "无效的类型",
        "blank": "不可为空",
        "min_length": "最少15个字"
    })

    # 自定义错误字段
    # 创建自定义独立字段question
    # required=True 字段不能为空
    # allow_null=True 字段允许为null
    # allow_blank=True 数据校验阶段,字段可以为null
    # write_only=True 字段只能写
    # read_only=True 字段只能读
    error = serializers.CharField(default="", required=False, allow_blank=True, allow_null=True)

    class Meta:
        model = models.SurveyQuestion
        fields = (
            "question",
            "id",
            "survey_type",
            "title",
            "choices",
            "value",
            "error"
        )

    # 定义全局钩子
    def validate(self, attrs):
        if attrs.get("survey_type") != "choice":
            if len(attrs["value"]) <= 15:
                raise serializers.ValidationError("填写内容不能少于15个字")

        return attrs

    # 自定制返回内容
    # 重写方法
    def to_internal_value(self, data):
        data["question"] = self.Meta.model.objects.get(pk=data["id"])

        return data


# 模板序列化器
class SurveyTemplateSerializer(serializers.ModelSerializer):
    # 层级序列化器方式二:通过直接指定类名(manytomany字段需要参数:many=True,foreignkey字段则不需要)
    questions = SurveyQuestionSerializer(many=True)

    class Meta:
        model = models.SurveyTemplate
        fields = (
            "id",
            "name",
            "questions",
        )


# 调查表序列化器
class SurveyDetailSerializer(serializers.ModelSerializer):
    # 层级序列化器方式一:通过ListSerializer指定(child=指定需要关联子序列化类)
    # read_only 只允许读
    # 只有manytomany字段需要指定many=True,其他foreignkey字段或者onetoone字段不需要指定many参数
    survey_templates = serializers.ListSerializer(child=SurveyTemplateSerializer(), read_only=True)

    class Meta:
        model = models.Survey
        fields = (
            "id",
            "survey_templates"
        )

四、序列化器的数据校验(局部钩子与全局钩子函数)

  4.1 定义钩子函数进行数据校验:

  注:rest_framework 钩子函数源码 从  is_valid 入口

语法: validate + 校验字段名

from rest_framework.exceptions import ValidationError
class BookSerialize(serializers.ModelSerializer):
    class Meta:
        model = models.Author
        fields = '__all__'  # 序列化所有字段 一般不用

     # 局部钩子 写在序列化组件里
    def validate_name(self,value):
        if value.startswith("sb"):
                raise ValidationError("不能以sb开头")
        return value

    # 全局钩子  所有字段校验通过
    def validate(self, value):
        name = value.get("name")
        price = value.get("price")
        if name != price:
            raise ValidationError("书与价格不能比较")
        return value

  4.2 通过重写父类方法进行数据校验:

  注意:当前视图函数继承CreateAPIView类

from rest_framework.exceptions import ValidationError
class BookSerialize(serializers.ModelSerializer):
    class Meta:
        model = models.Author
        fields = '__all__'  # 序列化所有字段 一般不用

    # 创建新数据
    # 重写CreateAPIView中的create方法
    def create(self, validated_data):
        validated_data.pop("price", None)  # 删除当前无用字段
        return super(SurveyCreateSerializer, self).create(validated_data)

五、序列化器自定义字段

class SurveyQuestionSerializer(serializers.ModelSerializer):
    # 自定义字段方式一
    error = serializers.CharField(default="", required=False, allow_blank=True, allow_null=True)

   # 自定义字段方式二
  # 重写父类方法
  def to_representation(self, instance): data = super(SurveyQuestionSerializer, self).to_representation(instance) data["name"] = "xxx" # 自定义字段 return data class Meta: model = models.SurveyQuestion fields = ( "error", "id", "title""name" )

 

posted @ 2019-09-10 22:32  Amorphous  阅读(395)  评论(0编辑  收藏  举报