序列化和表單驗證

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()
相關文章
相關標籤/搜索