Serializer

Posted tangshuo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Serializer相关的知识,希望对你有一定的参考价值。

API

serializers.Serializer

序列化

read_only = True

choice字段

  category = serializers.ChoiceField(
        choices=CHOICES, source=‘get_category_display‘)

一对多 & 多对多

先把其他序列化类(publisherserializer,authorserializer)写完

通过有没有many = True来区分 一对多和多对多

   publisher = PublisherSerializer() # 一对多
   author = AuthorSerializer(many=True)  # 多对多
    def get(self, request):
        # book_obj = Book.objects.first()
        # serializer = BookSerilizer(book_obj)  ## 通过data区分是get 还是post
 
        book_list = Book.objects.all()
        serializer = BookSerilizer(book_list, many=True)  ## 通过data区分是get 还是post
        return Response(serializer.data) 

反序列化

write_only = True

注意事项

  • 看源码

  • 分析前端传什么字段,区分不同的字段

  •     def post(self, request):
            book_obj = request.data
            serializer = BookSerilizer(data=book_obj) ## 通过data区分 是get还是post请求
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data)
            return Response(serializer.errors)
    
  • serializer 要重写 cerate方法 ==》 看源码 返回值

        def create(self, validated_data):
            book_obj = Book.objects.create(
                title=validated_data[‘title‘],
                category=validated_data[‘s_category‘],
                pub_time=validated_data[‘pub_time‘],
                publisher_id=validated_data[‘s_publisher‘])
            book_obj.author.add(*validated_data[‘s_author‘])
            return book_obj
    

serializers.ModelSerializer

一对多 多对多 choice字段

extra_kwargs
    def get_s_category(self,obj):
        return obj.get_category_display()     # choice
 
    def get_s_author(self, obj):                 # 多对对
        author_queryset = Author.objects.all()
        return [{"title": item.name} for item in author_queryset]
 
    def get_s_publisher(self, obj):     # 一对多
        return obj.publisher.title   
 

校验

validate_字段(self,value)

#     def validate_title(self, value):
#         if "python" not in value.lower():
#             raise serializers.ValidationError("标题必须含有python")
#         return value

valudate(self,attrs)

#     def validate(self, attrs):
#         if attrs["w_category"] == 1 and attrs["publisher_id"] == 1:
#             return attrs
#         else:
#             raise serializers.ValidationError("分类以及标题不符合要求")

自定义函数校验

def my_validate(value):
    if "敏感信息" in value.lower():
        raise serializers.ValidationError("不能含有敏感信息")
    else:
        return value

回顾

APIView ( 可以 )

from rest_framework.response import Response
class UserModelSerializer(serializers.ModelSerializer):
   class Meta:
       model = models.UserInfo
       fields = "__all__"

class UserView(APIView):

   def get(self,request,*args,**kwargs):
       user_list = models.UserInfo.objects.all()
       ser = UserModelSerializer(instance=user_list,many=True)
       return Response(ser.data)

   def post(self,request,*args,**kwargs):
       ser = UserModelSerializer(data=request.data)
       if ser.is_valid():
           # models.UserInfo.objects.create(**ser.validated_data)
           ser.save(user_id=1)
           return Response(ser.data)
       return Response(ser.errors)

ListAPIView

ListAPIView,CreateAPIView,RetrieveAPIView,UpdateAPIView,DestroyAPIView

class NewTestModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.News
        fields = "__all__"

class NewTestView(CreateAPIView,ListAPIView):
    serializer_class = NewTestModelSerializer
    queryset = models.News.objects.filter(id__gt=4)

用户传一些值

创建用户时,自己在后台生成一个UID。

class NewTestModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.News
        fields = "__all__"

class NewTestView(CreateAPIView,ListAPIView):
    serializer_class = NewTestModelSerializer
    queryset = models.News.objects.filter(id__gt=4)

    def perform_create(self, serializer):
        serializer.save(uid=str(uuid.uuid4()))

fields和exclude的区别?

通过fields和exclude定制页面展示数据。

需求:只显示用户表的id,name,age的数据,其他不显示。

class NewTestModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.News
        # fields = ["id","name",‘age‘]
        # fields = "__all__"
        exclude = [‘gender‘]

class NewTestView(ListAPIView):
    serializer_class = NewTestModelSerializer
    queryset = models.User.objects.all()
    
[
    {id:1,name:‘xxx‘,age:18},
    {id:1,name:‘xxx‘,age:11},
    {id:1,name:‘xxx‘,age:99},
]

需求:数据库有5个字段,显示7个字段。

class NewTestModelSerializer(serializers.ModelSerializer):
    xx = serializers.CharField(source=‘id‘)
    x1 = serializers.SerializerMethodField()
    class Meta:
        model = models.News
        # fields = "__all__"
        # fields = [‘id‘,‘name‘,‘age‘,‘gender‘,‘phone‘,‘xx‘,‘x1‘]
        exclude = [‘id‘,‘name‘]
    
    def get_x1(self,obj):
        return obj.id
    
class NewTestView(ListAPIView):
    serializer_class = NewTestModelSerializer
    queryset = models.User.objects.all()
    
[
    {id:1,name:‘xxx‘,age:18...   xx:1,x1:1},
    {id:2,name:‘xxx‘,age:11...   xx:2,x1:2},
    {id:3,name:‘xxx‘,age:99,     xx:3,x1:3},
]

read_only

添加时不要,查看时候需要。

需求:编写两个接口 添加(3字段)、获取列表(5个字段)

class NewTestModelSerializer(serializers.ModelSerializer):
    # phone = serializers.CharField(source=‘phone‘,read_only=True)
    # email = serializers.CharField(source=‘email‘,read_only=True)
    class Meta:
        model = models.News
        fields = "__all__"
        read_only_fields = [‘phone‘,‘email‘,]
        
class NewTestView(CreateAPIView, ListAPIView):
    serializer_class = NewTestModelSerializer
    queryset = models.User.objects.all()
    
添加:
    {
        name:‘xx‘,
        age:‘19‘,
        gender:1
    }
获取:
    [
        {name:‘xx‘,age:‘xx‘,gender:‘‘,phone:‘xx‘,email:xxx}
    ]

复杂需求

添加时用一个serializers、列表时用一个serializers

class NewTestModelSerializer1(serializers.ModelSerializer):
    class Meta:
        model = models.News
        fields = "__all__"
        
class NewTestModelSerializer2(serializers.ModelSerializer):
    class Meta:
        model = models.News
        fields = "__all__"

class NewTestView(CreateAPIView, ListAPIView):
    queryset = models.User.objects.all()
    
    def get_serializer_class(self):
        if self.request.method == ‘POST‘:
            return NewTestModelSerializer1
        if self.request.method == ‘GET‘:
            return NewTestModelSerializer2

serializers嵌套

class CreateNewsTopicModelSerializer(serializers.Serializer):
    key = serializers.CharField()
    cos_path = serializers.CharField()


class CreateNewsModelSerializer(serializers.ModelSerializer):
    imageList = CreateNewsTopicModelSerializer(many=True)

    class Meta:
        model = models.News
        exclude = [‘user‘, ‘viewer_count‘, ‘comment_count‘,"favor_count"]

    def create(self, validated_data):
        # 把imageList切走
        image_list = validated_data.pop(‘imageList‘)

        # 创建New表中的数据
        news_object = models.News.objects.create(**validated_data)

        data_list = models.NewsDetail.objects.bulk_create(
            [models.NewsDetail(**info, news=news_object) for info in image_list]
        )
        news_object.imageList = data_list

        if news_object.topic:
            news_object.topic.count += 1
            news_object.save()

        return news_object

class NewsView(CreateAPIView):
    """
    发布动态
    """
    serializer_class = CreateNewsModelSerializer
    def perform_create(self, serializer):
        # 只能保存:News表中的数据()
        # 调用serializer对象的save(先调用create)
        new_object = serializer.save(user_id=1)
        return new_object


Other

手机号校验

from rest_framework import serializers
from rest_framework.exceptions import ValidationError
import re


def phone_validator(value):
    if not re.match(r"^(1[3|4|5|6|7|8|9])d{9}$", value):
        raise ValidationError(‘手机格式错误‘)


class MessageSerializer(serializers.Serializer):
    phone = serializers.CharField(label=‘手机号‘, validators=[phone_validator, ])

serializer互相嵌套

API

serializers.Serializer

序列化

read_only = True

choice字段

  category = serializers.ChoiceField(
        choices=CHOICES, source=‘get_category_display‘)

一对多 & 多对多

先把其他序列化类(publisherserializer,authorserializer)写完

通过有没有many = True来区分 一对多和多对多

   publisher = PublisherSerializer() # 一对多
   author = AuthorSerializer(many=True)  # 多对多
    def get(self, request):
        # book_obj = Book.objects.first()
        # serializer = BookSerilizer(book_obj)  ## 通过data区分是get 还是post
 
        book_list = Book.objects.all()
        serializer = BookSerilizer(book_list, many=True)  ## 通过data区分是get 还是post
        return Response(serializer.data) 

反序列化

write_only = True

注意事项

  • 看源码

  • 分析前端传什么字段,区分不同的字段

  •     def post(self, request):
            book_obj = request.data
            serializer = BookSerilizer(data=book_obj) ## 通过data区分 是get还是post请求
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data)
            return Response(serializer.errors)
    
  • serializer 要重写 cerate方法 ==》 看源码 返回值

        def create(self, validated_data):
            book_obj = Book.objects.create(
                title=validated_data[‘title‘],
                category=validated_data[‘s_category‘],
                pub_time=validated_data[‘pub_time‘],
                publisher_id=validated_data[‘s_publisher‘])
            book_obj.author.add(*validated_data[‘s_author‘])
            return book_obj
    

serializers.ModelSerializer

一对多 多对多 choice字段

extra_kwargs
    def get_s_category(self,obj):
        return obj.get_category_display()     # choice
 
    def get_s_author(self, obj):                 # 多对对
        author_queryset = Author.objects.all()
        return [{"title": item.name} for item in author_queryset]
 
    def get_s_publisher(self, obj):     # 一对多
        return obj.publisher.title   
 

校验

validate_字段(self,value)

#     def validate_title(self, value):
#         if "python" not in value.lower():
#             raise serializers.ValidationError("标题必须含有python")
#         return value

valudate(self,attrs)

#     def validate(self, attrs):
#         if attrs["w_category"] == 1 and attrs["publisher_id"] == 1:
#             return attrs
#         else:
#             raise serializers.ValidationError("分类以及标题不符合要求")

自定义函数校验

def my_validate(value):
    if "敏感信息" in value.lower():
        raise serializers.ValidationError("不能含有敏感信息")
    else:
        return value

回顾

APIView ( 可以 )

from rest_framework.response import Response
class UserModelSerializer(serializers.ModelSerializer):
   class Meta:
       model = models.UserInfo
       fields = "__all__"

class UserView(APIView):

   def get(self,request,*args,**kwargs):
       user_list = models.UserInfo.objects.all()
       ser = UserModelSerializer(instance=user_list,many=True)
       return Response(ser.data)

   def post(self,request,*args,**kwargs):
       ser = UserModelSerializer(data=request.data)
       if ser.is_valid():
           # models.UserInfo.objects.create(**ser.validated_data)
           ser.save(user_id=1)
           return Response(ser.data)
       return Response(ser.errors)

ListAPIView

ListAPIView,CreateAPIView,RetrieveAPIView,UpdateAPIView,DestroyAPIView

class NewTestModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.News
        fields = "__all__"

class NewTestView(CreateAPIView,ListAPIView):
    serializer_class = NewTestModelSerializer
    queryset = models.News.objects.filter(id__gt=4)

用户传一些值

创建用户时,自己在后台生成一个UID。

class NewTestModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.News
        fields = "__all__"

class NewTestView(CreateAPIView,ListAPIView):
    serializer_class = NewTestModelSerializer
    queryset = models.News.objects.filter(id__gt=4)

    def perform_create(self, serializer):
        serializer.save(uid=str(uuid.uuid4()))

fields和exclude的区别?

通过fields和exclude定制页面展示数据。

需求:只显示用户表的id,name,age的数据,其他不显示。

class NewTestModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.News
        # fields = ["id","name",‘age‘]
        # fields = "__all__"
        exclude = [‘gender‘]

class NewTestView(ListAPIView):
    serializer_class = NewTestModelSerializer
    queryset = models.User.objects.all()
    
[
    {id:1,name:‘xxx‘,age:18},
    {id:1,name:‘xxx‘,age:11},
    {id:1,name:‘xxx‘,age:99},
]

需求:数据库有5个字段,显示7个字段。

class NewTestModelSerializer(serializers.ModelSerializer):
    xx = serializers.CharField(source=‘id‘)
    x1 = serializers.SerializerMethodField()
    class Meta:
        model = models.News
        # fields = "__all__"
        # fields = [‘id‘,‘name‘,‘age‘,‘gender‘,‘phone‘,‘xx‘,‘x1‘]
        exclude = [‘id‘,‘name‘]
    
    def get_x1(self,obj):
        return obj.id
    
class NewTestView(ListAPIView):
    serializer_class = NewTestModelSerializer
    queryset = models.User.objects.all()
    
[
    {id:1,name:‘xxx‘,age:18...   xx:1,x1:1},
    {id:2,name:‘xxx‘,age:11...   xx:2,x1:2},
    {id:3,name:‘xxx‘,age:99,     xx:3,x1:3},
]

read_only

添加时不要,查看时候需要。

需求:编写两个接口 添加(3字段)、获取列表(5个字段)

class NewTestModelSerializer(serializers.ModelSerializer):
    # phone = serializers.CharField(source=‘phone‘,read_only=True)
    # email = serializers.CharField(source=‘email‘,read_only=True)
    class Meta:
        model = models.News
        fields = "__all__"
        read_only_fields = [‘phone‘,‘email‘,]
        
class NewTestView(CreateAPIView, ListAPIView):
    serializer_class = NewTestModelSerializer
    queryset = models.User.objects.all()
    
添加:
    {
        name:‘xx‘,
        age:‘19‘,
        gender:1
    }
获取:
    [
        {name:‘xx‘,age:‘xx‘,gender:‘‘,phone:‘xx‘,email:xxx}
    ]

复杂需求

添加时用一个serializers、列表时用一个serializers

class NewTestModelSerializer1(serializers.ModelSerializer):
    class Meta:
        model = models.News
        fields = "__all__"
        
class NewTestModelSerializer2(serializers.ModelSerializer):
    class Meta:
        model = models.News
        fields = "__all__"

class NewTestView(CreateAPIView, ListAPIView):
    queryset = models.User.objects.all()
    
    def get_serializer_class(self):
        if self.request.method == ‘POST‘:
            return NewTestModelSerializer1
        if self.request.method == ‘GET‘:
            return NewTestModelSerializer2

serializers嵌套

class CreateNewsTopicModelSerializer(serializers.Serializer):
    key = serializers.CharField()
    cos_path = serializers.CharField()


class CreateNewsModelSerializer(serializers.ModelSerializer):
    imageList = CreateNewsTopicModelSerializer(many=True)

    class Meta:
        model = models.News
        exclude = [‘user‘, ‘viewer_count‘, ‘comment_count‘,"favor_count"]

    def create(self, validated_data):
        # 把imageList切走
        image_list = validated_data.pop(‘imageList‘)

        # 创建New表中的数据
        news_object = models.News.objects.create(**validated_data)

        data_list = models.NewsDetail.objects.bulk_create(
            [models.NewsDetail(**info, news=news_object) for info in image_list]
        )
        news_object.imageList = data_list

        if news_object.topic:
            news_object.topic.count += 1
            news_object.save()

        return news_object

class NewsView(CreateAPIView):
    """
    发布动态
    """
    serializer_class = CreateNewsModelSerializer
    def perform_create(self, serializer):
        # 只能保存:News表中的数据()
        # 调用serializer对象的save(先调用create)
        new_object = serializer.save(user_id=1)
        return new_object


Other

手机号校验

from rest_framework import serializers
from rest_framework.exceptions import ValidationError
import re


def phone_validator(value):
    if not re.match(r"^(1[3|4|5|6|7|8|9])d{9}$", value):
        raise ValidationError(‘手机格式错误‘)


class MessageSerializer(serializers.Serializer):
    phone = serializers.CharField(label=‘手机号‘, validators=[phone_validator, ])

serializer互相嵌套

技术图片

images = NewsDetailModelSerializer(Many=True)  ==> images字段 [ {},{} ... ]

images = NewsDetailModelSerializer(Many=True)  ==> images字段 [ {},{} ... ]

以上是关于Serializer的主要内容,如果未能解决你的问题,请参考以下文章

DRF框架serializer之ModelSerializer

Undefined class constant 'SERIALIZER_IGBINARY' 解决方法

将数据从post传递给Serializer

序列化器关系 (Serializer relations)

序列化器关系 (Serializer relations)

Serializer组件(序列化器-Serializer)