Django到DjangoRestFramework - 我在哪里进行表单验证(我不再使用forms.py - 我使用serializers.py)

时间:2015-09-29 02:31:03

标签: django forms validation django-rest-framework django-serializer

我曾经只使用Django,但最近开始使用DjangoRestFramework。没有DjangoRestFramework,这是我的forms.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)

数据发布到的网址是&#34; / users&#34;处理它的视图是:

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():

话虽如此,由于我不再使用RegistrationForm,因此不会执行额外的clean_username()和clean_password2()函数。在我没有使用DRF时,我曾经做过表格验证的正确位置在哪里?

1 个答案:

答案 0 :(得分:2)

要在序列化程序中执行validation,我们可以定义一个函数validate_username()来验证用户名,另一个函数validate()验证password1password2

自定义字段级验证:

我们需要验证username,我们可以为序列化程序添加函数validate_username()

要指定自定义字段级验证,我们需要将.validate_<field_name>方法添加到我们的Serializer子类中。这些类似于Django表单上的.clean_<field_name>方法。

  

这些方法采用单个参数,即字段值   需要验证。

     

您的validate_<field_name>方法应返回经过验证的值   或者提出serializers.ValidationError

对象级验证:

要进行需要访问多个字段的任何其他验证,我们需要在Serializer子类中添加一个名为.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