rest

    xiaoxiao2022-05-12  137

    序列化方式

    方式一

    from rest_framework.views import APIView from django.shortcuts import render, HttpResponse import json class PublishView(APIView): def get(self, request): publish_list = list(Publish.objects.all().values('title', 'email')) return HttpResponse(json.dumps(publish_list))

    方式二

    from django.core import serializers from rest_framework.views import APIView from django.shortcuts import render, HttpResponse class PublishView(APIView): def get(self, request): publish_list = Publish.objects.all() ret = serializers.serialize('json', publish_list) return HttpResponse(ret)

    方式三

    from rest_framework.views import APIView from rest_framework.response import Response from app01.Serializers import * class PublishView(APIView): def get(self, request): publish_list = Publish.objects.all() ret = PublishSerializer(publish_list, many=True) return Response(ret.data)

    app01.Serializers.py

    from rest_framework import serializers class PublishSerializer(serializers.Serializer): title = serializers.CharField() email = serializers.CharField()

     方式四

    from rest_framework.views import APIView from rest_framework.response import Response from app01.Serializers import * class PublishView(APIView): def get(self, request): publish_list = Publish.objects.all() ret = PublishModelSerializer(publish_list, many=True) return Response(ret.data)

    app01.Serializers.py

    from rest_framework import serializers class PublishModelSerializer(serializers.ModelSerializer): class Meta: model = Publish fields = "__all__"

    详细介绍方式四

    继承serializers.ModelSerializer类,需要在序列化类中定义Meta类

    Meta常用的参数

    model:需要被序列化的类 list_serializer_class:批量序列化时调用的序列化类,在调用序列化类传入多个对象组成的列表或集合时,需要传入关键字参数many=True,将调用这个类。一般不需要配置这个类 fields:需要被序列化的字段组成的列表或元祖,值为"__all__"时表示全部字段 exclude:不被序列化的字段主城的列表或元祖,与fields不能同时用

    使用方法

    class Meta: model = Dynamic list_serializer_class = DynamicsListSerializer # 另一个序列化类 # fields="__all__" # 不能与exclude 一起用 exclude = ["字段一", "字段二", "字段三"]

    serializers.SerializerMethodField()

    序列化的结果中需要有模型类中没有的字段时,将会使用到这个对象,需要重写个钩子方法。

    使用方法

    gender = serializers.SerializerMethodField() def get_gender(self, obj): ''' 配合gender定义的钩子方法,方法名必须是get_自定义字段名,参数obj是Meta中model指定类的实例对象 ''' return obj.user.gender

     序列化类做数据校验

    在收到前端传到后台的数据后,可以使用序列化类进行数据校验。

    user = serializers.CharField(source='user.pk', required=False, allow_blank=True, error_messages={ 'required': "User value can not be empty", })

    序列化类使用这种方式时,既可以对数据做序列化也可以对数据进行校验

    例如这里的user字段,原本的模型类里的user字段作为外键关联到另外一个类,如果不做处理,直接序列化,序列化结果中user字段的值将是user模型类的__str__()方法的返回值。声明参数source='user.pk',序列化的结果将是user的主键值。

    required的值是True时,将会对该字段为必须参数,False允许不传

    allow_blank值为True,该字段的值可以为空字符串,默认为False

    error_messages值是字典类型,key为该字段的约束名,value为违反约束后的提示信息

    phone = serializers.CharField(max_length=11, required=True, error_messages={ 'max_length': 'Phone number length exceeds 11', 'required': "Phone value can not be empty" })

    此外,还可以使用钩子方法校验数据

    局部钩子

    def validate_phone(self, attrs): r = re.compile(r"^1((3[0-9])|(4[5,7])|(5[0-3,5-9])|(7[0,3,5-8])|(8[0-9])|66|98|99|47)\d{8}") if not isinstance(attrs, str): raise exceptions.ValidationError("Phone number type error") if not r.match(attrs): raise exceptions.ValidationError("Phone number is error") return attrs

    这个示例钩子方法会验证模型类中的phone字段,参数attrs即前端传入的phone字段的值,如果通过校验则返回该值,否则主动抛出exceptions.ValidationError异常

    全局钩子

    def validate(self, attrs): if not attrs['detail'] and not attrs['photos']: raise exceptions.ValidationError("Detail and Photos cannot be empty at the same time") return attrs

    全局钩子方法是在所有局部钩子运行完毕后才运行的方法,参数attrs是字典型的全部需要校验的数据,如果通过校验则返回attrs,否则主动抛出exceptions.ValidationError异常

    有时候未完成自定义功能需要重写父类的方法,如现有一个需求需要将前端传入过来的的多个图片链接拼接成字符串存入数据库,且图片链接用","隔开。

    对于接收前端传过来的图片链接组成的列表可以使用

    photos = serializers.ListField(required=True, error_messages={ 'required': "Photos value can not be empty" })

    但是想要序列化该类的对象,却可能会发现序列化后的数据中photos字段对应的也是一个列表,但是这个列表很特殊,使用''.join(photos )拼接后正好是数据库中存的图片链接拼接后的字符串。对于这种数据前端是无法直接使用的。为了解决这个问题,可以重写父类的data方法。

    @property def data(self): ret = super(CircleUserSerializer, self).data if isinstance(ret, dict): ret['photos'] = ''.join(ret['photos']).split(',') return ret

    为了能批量序列化该类,需要重新写一个继承serializers.ListSerializer的序列化类

    class CircleUserListSerializer(serializers.ListSerializer): @property def data(self): ret = super(CircleUserListSerializer, self).data for _ in ret: _['photos'] = ''.join(_['photos']).split(',') return ret

    因为序列化对象需要调用data方法返回序列化数据,所以重写data方法是最简单的解决办法。

    在使用序列化类的反序列化功能时,有时候遇到模型类中有多对多映射或一对多映射的字段时,默认的序列化类将不能根据传入的数据实例化成对象。解决这个问题就需要重写serializers.ModelSerializer类的create方法。

    def create(self, validated_data): photos=validated_data.pop('photos') dynamic= Dynamic.objects.create(**validated_data) for photo in photos: Photo.objects.create(src=photo,dynamic=dynamic) return dynamic

    下面是部分实例代码

    from rest_framework import serializers from rest_framework import exceptions from .models import CircleUser class CircleUserListSerializer(serializers.ListSerializer): @property def data(self): ret = super(CircleUserListSerializer, self).data for _ in ret: _['photos'] = ''.join(_['photos']).split(',') return ret class CircleUserSerializer(serializers.ModelSerializer): class Meta: model = CircleUser list_serializer_class = CircleUserListSerializer # fields = "__all__" exclude = ['app_id', 'session_key'] phone = serializers.CharField(max_length=11, required=True, error_messages={ 'max_length': 'Phone number length exceeds 11', 'required': "Phone value can not be empty" }) career = serializers.CharField(max_length=128, required=True, error_messages={ 'max_length': "Career value length exceeds 128", 'required': "Career value can not be empty" }) child_introduction = serializers.CharField(max_length=140, required=True, error_messages={ 'max_length': "Child_introduction value length exceeds 140", 'required': "Child_introduction value can not be empty" }) spouse_description = serializers.CharField(max_length=140, required=False, allow_blank=True, error_messages={ 'max_length': "Spouse_description value length exceeds 140", }) photos = serializers.ListField(required=True, error_messages={ 'required': "Photos value can not be empty" }) def validate_phone(self, attrs): r = re.compile(r"^1((3[0-9])|(4[5,7])|(5[0-3,5-9])|(7[0,3,5-8])|(8[0-9])|66|98|99|47)\d{8}") if not isinstance(attrs, str): raise exceptions.ValidationError("Phone number type error") if not r.match(attrs): raise exceptions.ValidationError("Phone number is error") return attrs def validate_career(self, attrs): if not isinstance(attrs, str): raise exceptions.ValidationError("Career value type error") return attrs def validate_child_introduction(self, attrs): if not isinstance(attrs, str): raise exceptions.ValidationError("Child_introduction value type error") return attrs def validate_photos(self, attrs): if not isinstance(attrs, list): raise exceptions.ValidationError("Photos value type error") if not attrs: raise exceptions.ValidationError("Photos value can not be empty") url_complie = re.compile(r'(http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?') for _ in attrs: if not url_complie.match(_): raise exceptions.ValidationError("Photo url is error") return attrs @property def data(self): ret = super(CircleUserSerializer, self).data if isinstance(ret, dict): ret['photos'] = ''.join(ret['photos']).split(',') return ret

     


    最新回复(0)