1

我過去只使用Django,但最近開始使用DjangoRestFramework。如果沒有DjangoRestFramework,這是我forms.py:Django DjangoRestFramework - 我在哪裏做表單驗證(我不再使用forms.py - 我正在使用serializers.py)

class RegistrationForm(forms.Form): 

    username = forms.CharField(label='Username', max_length=30) 
    email = forms.EmailField(label='Email') 
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput()) 
    password2 = forms.CharField(label='Confirm Password', widget=forms.PasswordInput()) 

    def clean_password2(self): 
     if 'password1' in self.cleaned_data: 
      password1 = self.cleaned_data['password1'] 
      password2 = self.cleaned_data['password2'] 
     if password1 == password2: 
      return password2 
     raise forms.ValidationError('Passwords do not match.') 

    def clean_username(self): 
     username = self.cleaned_data['username'] 
     if not re.search(r'^\w+$', username): 
      raise forms.ValidationError('Username can only contain alphanumeric characters and the underscore.') 
     try: 
      User.objects.get(username=username) 
     except ObjectDoesNotExist: 
      return username 
     raise forms.ValidationError('Username is already taken.') 

我用來傳遞這種形式的前端,然後當用戶填好後點擊提交,在後臺我只想做:

if form.is_valid(): 

驗證表單是否有效。但是,現在我正在使用DRF和序列化器,我沒有任何forms.py文件。我只是在前端創建表單,像這樣:

<form ng-submit="ctrl.add()"> 
    <label>Username</label> 
    <input type="text" ng-model="ctrl.user.username"> 

    <label>Password</label> 
    <input type="password" ng-model="ctrl.user.password"> 

    <label>Confirm Password</label> 
    <input type="password" ng-model="ctrl.user.passwordTwo"> 

    <label>Email</label> 
    <input type="email" ng-model="ctrl.user.email"> 

    <input type="submit" value="Register"> 
</form> 

,當用戶點擊提交,AngularJS它發送給後端,像這樣:

self.add = function() { 
    $http.post("/users", self.user) 

數據發佈到URL是「/用戶」,並處理它是視圖:

class user_list(APIView): 
    """ 
    Create a new user. 
    """ 

    def post(self, request): 
     serializer = UserSerializer(data=request.DATA) 
     if serializer.is_valid(): 
      serializer.save() 
      return Response(serializer.data, status=status.HTTP_201_CREATED) 
     return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 

所以當我做驗證發生:

if serializer.is_valid(): 

這樣說,額外的clean_username()和clean_password2()函數不會得到執行,因爲我不再使用RegistrationForm。在我不使用DRF時,我做過的表單驗證的正確位置在哪裏?

回答

2

要在串行執行validation,我們可以定義一個函數validate_username()這將驗證用戶名和另一個功能validate()這驗證password1password2

自定義字段級驗證:

我們需要驗證username,我們可以添加一個功能validate_username()我們的序列化。

要指定自定義字段級驗證,我們需要將.validate_<field_name>方法添加到我們的序列化器子類。這些是類似於Django表單上的.clean_<field_name>方法。

這些方法採取一個參數,它是字段值 需要驗證。

您的validate_<field_name>方法應返回驗證值 或提高serializers.ValidationError

對象級別的驗證:

要做到這一點,需要訪問多個字段的任何其他驗證,我們需要一個叫做.validate()方法添加到我們的串行子類。

此方法只接受一個參數,它是一個字段值的字典。如果有必要,它應該提高ValidationError,或者只是返回驗證的值。

由於在clean_password2()功能,您要還可以訪問的password1的價值,我們需要定義一個validate()函數來完成對象級檢驗。

終極密碼:

from rest_framework import serializers 

class UserSerializer(serializers.ModelSerializer): 

    ... 

    def validate_username(self, value):   
     if not re.search(r'^\w+$', value): 
      raise serializers.ValidationError('Username can only contain alphanumeric characters and the underscore.') 
     if User.objects.filter(username=value): 
      raise serializers.ValidationError('Username is already taken.') 
     return value # must return validated value 

    def validate(self, data): 
     password1 = data.get('password1') 
     password2 = data.get('password2') 
     if password1 != password2: 
      raise serializers.ValidationError('Passwords do not match.') 
     return data # must return validated values