我试图将django validators 1.9与django rest框架序列化器集成。但序列化的用户' (django rest framework)与django验证器不兼容。
这是serializers.py
import django.contrib.auth.password_validation as validators
from rest_framework import serializers
class RegisterUserSerializer(serializers.ModelSerializer):
password = serializers.CharField(style={'input_type': 'password'}, write_only=True)
class Meta:
model = User
fields = ('id', 'username', 'email, 'password')
def validate_password(self, data):
validators.validate_password(password=data, user=User)
return data
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
user.is_active = False
user.save()
return user
我设法将MinimumLengthValidator和NumericPasswordValidator设置为正确,因为两个函数验证都没有使用' user'在验证。源代码为here
摘自django源代码:
def validate(self, password, user=None):
if password.isdigit():
raise ValidationError(
_("This password is entirely numeric."),
code='password_entirely_numeric',
)
对于像UserAttributeSimilarityValidator这样的其他验证器,该函数使用另一个参数' user'在验证中('用户'是django用户模型,如果我没有错)
摘自django源代码:
def validate(self, password, user=None):
if not user:
return
for attribute_name in self.user_attributes:
value = getattr(user, attribute_name, None)
如何将序列化用户更改为django验证器(UserAttributeSimilarityValidator)可以看到的内容
摘自django源代码:
def validate(self, password, user=None):
if not user:
return
for attribute_name in self.user_attributes:
value = getattr(user, attribute_name, None)
if not value or not isinstance(value, string_types):
continue
修改
Django Rest Framework可以获得所有Django的内置密码验证(但它就像黑客一样)。这是一个问题:
validationError就像这样
[ValidationError(['此密码太短。必须包含at 至少8个字符。']),ValidationError(['此密码完全是 。数字'])]
验证不包含字段。 Django休息框架将其视为
{
"non_field_errors": [
"This password is too short. It must contain at least 8 characters.",
"This password is entirely numeric."
]
}
如何在raise ValidationError
答案 0 :(得分:15)
与您提到的一样,当您使用password
验证程序验证validate_password
方法中的UserAttributeSimilarityValidator
时,您没有user
对象。
我建议您不要进行字段级验证,而应通过在序列化程序上实现validate
方法来执行object-level validation:
import sys
from django.core import exceptions
import django.contrib.auth.password_validation as validators
class RegisterUserSerializer(serializers.ModelSerializer):
# rest of the code
def validate(self, data):
# here data has all the fields which have validated values
# so we can create a User instance out of it
user = User(**data)
# get the password from the data
password = data.get('password')
errors = dict()
try:
# validate the password and catch the exception
validators.validate_password(password=password, user=User)
# the exception raised here is different than serializers.ValidationError
except exceptions.ValidationError as e:
errors['password'] = list(e.messages)
if errors:
raise serializers.ValidationError(errors)
return super(RegisterUserSerializer, self).validate(data)
答案 1 :(得分:9)
即使在进行字段级验证时,您也可以通过序列化程序对象上的self.instance
访问用户对象。这样的事情应该有效:
from django.contrib.auth import password_validation
def validate_password(self, value):
password_validation.validate_password(value, self.instance)
return value
答案 2 :(得分:3)
使用序列化程序!有一个validate_fieldname
方法!
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = (
'id', 'username', 'password', 'first_name', 'last_name', 'email'
)
extra_kwargs = {
'password': {'write_only': True},
'username': {'read_only': True}
}
def validate_password(self, value):
try:
validate_password(value)
except ValidationError as exc:
raise serializers.ValidationError(str(exc))
return value
def create(self, validated_data):
user = super().create(validated_data)
user.set_password(validated_data['password'])
user.is_active = False
user.save()
return user
def update(self, instance, validated_data):
user = super().update(instance, validated_data)
if 'password' in validated_data:
user.set_password(validated_data['password'])
user.save()
return user
答案 3 :(得分:0)
在创建新用户(注册)时,self.instance将为none,它将在何时工作 您正在使用密码更改密码,更改密码或更新用户数据。 但是如果你想检查密码不应该与你的电子邮件或用户名类似,那么你需要包括" SequenceMatcher" 在您的验证中
data = self.get_initial()
username = data.get("username")
email = data.get("email")
password = data.get("password")
max_similarity = 0.7
if SequenceMatcher(a=password.lower(), b=username.lower()).quick_ratio() > max_similarity:
raise serializers.ValidationError("The password is too similar to the username.")
if SequenceMatcher(a=password.lower(), b=email.lower()).quick_ratio() > max_similarity:
raise serializers.ValidationError("The password is too similar to the email.")