1

我以前只使用 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)

数据发布到的 URL 是“/users”,处理它的视图是:

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 时进行表单验证的正确位置在哪里?

4

1 回答 1

2

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

自定义字段级验证:

我们需要验证,我们可以向我们的序列化username程序添加一个函数。validate_username()

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

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

您的validate_<field_name>方法应该返回经过验证的值或引发serializers.ValidationError.

对象级验证:

要进行需要访问多个字段的任何其他验证,我们需要添加一个调用.validate()到我们的 Serializer 子类的方法。

此方法采用单个参数,即字段值字典。ValidationError如有必要,它应该引发 a ,或者只返回经过验证的值。

由于在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
于 2015-09-29T02:45:39.860 回答