Django 到 DjangoRestFramework - 我在哪里进行表单验证(我不再使用 forms.py - 我正在使用 serializers.py)
Django to DjangoRestFramework - Where do I do form validation (I am no longer using forms.py - I'm using serializers.py)
我以前只使用 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():
也就是说,额外的 clean_username() 和 clean_password2() 函数不会执行,因为我不再使用 RegistrationForm。我以前不使用 DRF 时进行表单验证的正确位置在哪里?
要在序列化程序中执行 validation,我们可以定义一个函数 validate_username()
来验证用户名和另一个函数 validate()
来验证 password1
和 password2
.
自定义字段级验证:
我们需要验证 username
,我们可以向我们的序列化器添加一个函数 validate_username()
。
要指定自定义字段级验证,我们需要向 Serializer 子类添加 .validate_<field_name>
方法。这些 类似于 Django 表单上的 .clean_<field_name>
方法。
These methods take a single argument, which is the field value that
requires validation.
Your validate_<field_name>
methods should return the validated value
or raise a serializers.ValidationError
.
对象级验证:
要执行需要访问多个字段的任何其他验证,我们需要向我们的 Serializer 子类添加一个名为 .validate()
的方法。
此方法采用单个参数,即字段值字典。如有必要,它应该引发 ValidationError
,或者只是 return 验证值。
由于在 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
我以前只使用 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():
也就是说,额外的 clean_username() 和 clean_password2() 函数不会执行,因为我不再使用 RegistrationForm。我以前不使用 DRF 时进行表单验证的正确位置在哪里?
要在序列化程序中执行 validation,我们可以定义一个函数 validate_username()
来验证用户名和另一个函数 validate()
来验证 password1
和 password2
.
自定义字段级验证:
我们需要验证 username
,我们可以向我们的序列化器添加一个函数 validate_username()
。
要指定自定义字段级验证,我们需要向 Serializer 子类添加 .validate_<field_name>
方法。这些 类似于 Django 表单上的 .clean_<field_name>
方法。
These methods take a single argument, which is the field value that requires validation.
Your
validate_<field_name>
methods should return the validated value or raise aserializers.ValidationError
.
对象级验证:
要执行需要访问多个字段的任何其他验证,我们需要向我们的 Serializer 子类添加一个名为 .validate()
的方法。
此方法采用单个参数,即字段值字典。如有必要,它应该引发 ValidationError
,或者只是 return 验证值。
由于在 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