私は Djangoバリデータ 1.9をDjango RESTフレームワークシリアライザと統合しようとしています。しかし、シリアル化された 'user'(Django Restフレームワーク)は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
Validateはどちらも検証に「user」を使用しないため、MinimumLengthValidatorとNumericPasswordValidatorを正しく取得できました。ソースコードは here です
Djangoソースコードからの抜粋:
def validate(self, password, user=None):
if password.isdigit():
raise ValidationError(
_("This password is entirely numeric."),
code='password_entirely_numeric',
)
UserAttributeSimilarityValidatorのような他のバリデーターの場合、関数は検証に別の1つの引数 'user'を使用します( '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 validators(UserAttributeSimilarityValidator)can see
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([このパスワードは短すぎます。8文字以上である必要があります。 '])、ValidationError(['このパスワードは完全に数字です。 '])]]
検証にフィールドが含まれていません。 Django RESTフレームワーク
{
"non_field_errors": [
"This password is too short. It must contain at least 8 characters.",
"This password is entirely numeric."
]
}
raise ValidationError
にフィールドを挿入するにはどうすればよいですか
前述のように、password
バリデーターを使用してvalidate_password
メソッドでUserAttributeSimilarityValidator
を検証する場合、user
オブジェクトはありません。
フィールドレベルの検証を行う代わりに、シリアライザにvalidate
メソッドを実装して オブジェクトレベルの検証 を実行することをお勧めします。
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)
フィールドレベルの検証を行う場合でも、シリアライザオブジェクトのself.instance
を介してユーザーオブジェクトにアクセスできます。このようなものはうまくいくはずです:
from Django.contrib.auth import password_validation
def validate_password(self, value):
password_validation.validate_password(value, self.instance)
return value
シリアライザを使用してください! 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
新しいユーザー(登録)を作成する時点では、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.")