序列化和表单验证

Django rest framework之序列化和表单验证

一.Serilalizer(定制性好,具体参考官网)

串行器容许诸如查询集和模型实例复杂的数据转换为可随后被容易地呈现到机Python数据类型JSONXML或其余内容类型。序列化程序还提供反序列化,容许在首次验证传入数据后将解析后的数据转换回复杂类型。html

REST框架中的序列化程序与Django FormModelForm类的工做方式很是类似咱们提供了一个Serializer类,它为您提供了一种强大的通用方法来控制响应的输出,以及一个ModelSerializer类,它提供了一个有用的快捷方式来建立处理模型实例和查询集的序列化程序。数据库

每一个序列化器字段类构造函数至少采用这些参数。某些Field类采用其余特定于字段的参数,但应始终接受如下内容:django

read_only

只读字段包含在API输出中,但在建立或更新操做期间不该包含在输入中。任何错误包含在序列化程序输入中的“read_only”字段都将被忽略。api

将其设置为True以确保在序列化表示时使用该字段,但在反序列化期间建立或更新实例时不使用该字段。框架

默认为 Falseide

write_only

将其设置True为确保在更新或建立实例时可使用该字段,但在序列化表示时不包括该字段。函数

默认为 Falseui

required

一般,若是在反序列化期间未提供字段,则会引起错误。若是在反序列化期间不须要此字段,则设置为false。加密

将此设置为False还容许在序列化实例时从输出中省略对象属性或字典键。若是密钥不存在,它将不会包含在输出表示中。url

默认为True

default

若是设置,则给出默认值,若是未提供输入值,将使用该字段。若是未设置,则默认行为是根本不填充该属性。

default过程当中部分更新操做不适用。在部分更新的状况下,只有传入数据中提供的字段将返回一个验证值。

能够设置为函数或其余可调用函数,在这种状况下,将在每次使用时评估该值。调用时,它不会收到任何参数。若是callable有一个set_context方法,那么在每次获取值以前都会调用该方法,并将字段实例做为惟一参数。这与验证器的工做方式相同

序列化实例时,若是实例中不存在对象属性或字典键,则将使用默认值。

请注意,设置default值意味着不须要该字段。包含defaultrequired关键字参数都是无效的,而且会引起错误。

allow_null

一般,若是None传递给序列化程序字段,则会引起错误将此关键字参数设置为Trueif None应被视为有效值。

请注意,若是没有显式default,将此参数设置为True将暗示序列化输出defaultnull,但不暗示输入反序列化的默认值。

默认为 False

source

将用于填充字段的属性的名称。多是一个只接受self参数的方法,例如URLField(source='get_absolute_url'),或者可使用点分表示来遍历属性,例如EmailField(source='user.email')使用点分表示法序列化字段时,default若是任何对象不存在或在属性遍历期间为空,则可能须要提供值。

该值source='*'具备特殊含义,用于指示整个对象应该传递到该字段。这对于建立嵌套表示或者须要访问整个对象以肯定输出表示的字段很是有用。

默认为字段名称。

validators

应该应用于传入字段输入的验证程序函数列表,它会引起验证错误或只是返回。验证器函数一般应该提升serializers.ValidationError,可是Django的内置函数ValidationError也支持与Django代码库或第三方Django软件包中定义的验证器兼容。

error_messages

错误消息的错误代码字典。

label

一个简短的文本字符串,可用做HTML表单字段或其余描述性元素中字段的名称。

help_text

一个文本字符串,可用做HTML表单字段或其余描述性元素中字段的描述。

initial

应该用于预填充HTML表单字段值的值。你能够将一个callable传递给它,就像你对任何常规Django同样Field

import datetime from rest_framework import serializers class ExampleSerializer(serializers.Serializer): day = serializers.DateField(initial=datetime.date.today) 

style

键值对的字典,可用于控制渲染器应如何渲染字段。

这里的两个例子是'input_type''base_template'

# Use <input type="password"> for the input. password = serializers.CharField( style={'input_type': 'password'} )  # Use a radio input instead of a select input. color_channel = serializers.ChoiceField( choices=['red', 'green', 'blue'], style={'base_template': 'radio.html'} )
class SmsSerializer(serializers.Serializer):
    '''
    注册手机号和验证码序列化
    '''
    mobile = serializers.CharField(max_length=11,min_length=11)

    def validate_mobile(self, mobile):
        '''
        验证手机号码
        '''
        # 验证手机是否合法
        if not re.match(REGEX_MOBILE, mobile):
            raise serializers.ValidationError('手机号非法')
        # 手机是否注册
        if User.objects.filter(mobile=mobile).count():
            raise serializers.ValidationError('用户已经存在')
        on_minute_ago = datetime.now() - timedelta(hours=0, minutes=1, seconds=0)
        if VerifyCode.objects.filter(add_time__gt=on_minute_ago, mobile=mobile):
            raise serializers.ValidationError('距离上一次发送未超过60秒')
        return mobile

 

 

二.ModelSerializer

class UserRegSerializer(serializers.ModelSerializer):
    '''
    用户注册序列化
    '''
    # write_only=True,不会拿该字段来序列化,labe标签名,help_text:docs文档中description
    code = serializers.CharField(required=True, write_only=True, max_length=4, min_length=4, label='验证码',
                                 error_messages={
                                     "blank": "请输入验证码",
                                     "required": "验证码不能为空",
                                     "max_length": "验证码格式错误",
                                     "min_length": "验证码格式错误"
                                 },help_text='验证码')
    username = serializers.CharField(required=True, allow_blank=False,
                                     validators=[UniqueValidator(queryset=User.objects.all(), message='用户已经存在')])
    #style密文,write_only=True不返回,保存为明文
    password = serializers.CharField(style={"input_type":"password"},write_only=True)
    #重载create函数,保存为密文,该方法能够实现加密密码,还能够信号(分离性好)
    # def create(self, validated_data):
    #     user=super(UserRegSerializer,self).create(validated_data=validated_data)
    #     user.set_password(validated_data['password'])
    #     user.save()
    #     return user

    def validate_code(self, code):
        # 不用get,若是返回两条数据以上,会抛异常
        # try:
        #   verify_codes=VerifyCode.objects.get(mobile=self.initial_data['username'])
        # except VerifyCode.DoesNotExist as e:
        #     pass
        # except VerifyCode.MultipleObjectsReturned as e:
        #     pass
        verify_codes = VerifyCode.objects.filter(mobile=self.initial_data['username']).order_by('-add_time')
        if verify_codes:
            last_verfycode = verify_codes[0]
            five_minute_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
            if five_minute_ago > last_verfycode.add_time:
                raise serializers.ValidationError('验证码过时')
            if code != last_verfycode.code:
                raise serializers.ValidationError('验证码错误')
        else:
            raise serializers.ValidationError('验证码错误')

    # 做用于全部字段,将验证码删除,不是插入数据库的字段
    def validate(self, attrs):
        attrs["mobile"] = attrs["username"]
        del attrs["code"]
        return attrs

    class Meta:
        model = User
        fields = ('username', 'code', 'mobile', 'password')

三.动态设置Serializer(重载GenericAPIView中的get_serializer_class方法)

class UserViewset(mixins.CreateModelMixin,mixins.UpdateModelMixin,mixins.RetrieveModelMixin,viewsets.GenericViewSet):
    '''
    用户
    '''
    serializer_class = UserRegSerializer
    queryset = User.objects.all()
    authentication_classes = (JSONWebTokenAuthentication,authentication.SessionAuthentication)
    #更新,添加用户信息放在一块儿,是否登陆应该动态,注册不用登陆IsAuthenticated,该方法不行
    # permission_classes = (permissions.IsAuthenticated)

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user=self.perform_create(serializer)
        re_dict=serializer.data
        payload=jwt_payload_handler(user)
        re_dict['token']=jwt_encode_handler(payload)
        re_dict['name']=user.name if user.name else user.username
        headers = self.get_success_headers(serializer.data)
        return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers)

    def get_serializer_class(self):
        '''
        重载GenericAPIView中的get_serializer_class函数,调用不一样的序列化类,若是是create,
        就调用UserRegSerializer序列化,不然UserDetailSerializer序列化
        :return: 
        '''
        if self.action == 'retrieve':
            return UserDetailSerializer
        elif self.action == 'create':
            return UserRegSerializer
        return UserDetailSerializer

    def get_permissions(self):
        '''
        重载APIview中的get_perimissions函数,若是是新增用户则不用登陆,不然必须登陆
        :return: 
        '''
        if self.action == 'retrieve':
            return [permissions.IsAuthenticated()]
        elif self.action == 'create':
            return []
        return []

    def get_object(self):
        '''
        返回当前用户
        :return: 
        '''
        return self.request.user

    def perform_create(self, serializer):
        return serializer.save()
相关文章
相关标签/搜索