2016-04-04 18 views
5

django validators 1.9をdjango rest frameworkシリアライザと統合しようとしています。しかし、シリアル化された 'ユーザー'(django rest frameworkの)はdjangoバリデーターと互換性がありません。ここでdjangoのパスワードバリデーターをdjango rest frameworkと統合するvalidate_password

は、両方の機能の検証は、検証で「ユーザー」を使用していないので、私はMinimumLengthValidatorとNumericPasswordValidatorが正しい得ることができた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 

です。ソースコードはDjangoのソースコードからhere

の抜粋です:UserAttributeSimilarityValidatorのような他のバリデータについては

def validate(self, password, user=None): 
     if password.isdigit(): 
      raise ValidationError(
       _("This password is entirely numeric."), 
       code='password_entirely_numeric', 
      ) 

、機能が有効で、別の1つの引数「ユーザー」を使用して、私は「場合(「ユーザー」は、DjangoのUserモデルであります間違っていないメートル)Djangoのソースコードから

抜粋:

def validate(self, password, user=None): 
     if not user: 
      return 

     for attribute_name in self.user_attributes: 
      value = getattr(user, attribute_name, None) 

がどのように私はSERIALIZを変更することができます何ジャンゴバリ(UserAttributeSimilarityValidator)へのEDユーザーは、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) 
      if not value or not isinstance(value, string_types): 
       continue 

編集

Djangoの残りのフレームワークをビルトインパスワードの検証(ただし、ハックのようなものです)。 ValidationErrorをこの

のようなものです

[ValidationErrorを([ 'このパスワードが短すぎることが 8文字以上で含まれている必要があります。。'])、ValidationErrorを([ 'このパスワードは、次のとおりです。ここで問題です完全に 数字] '])]

検証にはフィールドが含まれていません。 Djangoの残りのフレームワークあなたが言及した同様

{ 
    "non_field_errors": [ 
     "This password is too short. It must contain at least 8 characters.", 
     "This password is entirely numeric." 
    ] 
} 

として、それを参照してくださいどのように私はあなたがUserAttributeSimilarityValidatorバリデータを使用してvalidate_password方法でpasswordを検証するとき、あなたはuserオブジェクトを持っていない、raise ValidationError

答えて

8

でフィールドを注入することができます。私が代わりにフィールド・レベルの検証を行うための、あなたはシリアライザに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) 
+0

あなたの検証に を「はSequenceMatcher」を含める必要があります。ちなみに、あなたのソリューションは検証では正常に動作しますが、django restフレームワークはフィールド名を取得できません。したがって、non_field_errors ---> { "non_field_errors":[ "パスワードは電子メールに似ています。"、 "このパスワードは短すぎます。パスワードは8文字以上である必要があります。 ] } – momokjaaaaa

+0

私は実際にコードをテストしていないので、ここにいくつかのタイプミスがあるかもしれませんが、このコードを正しく使用しテストするのを止めてはいけません。 'NON_FIELD_ERRORS'について私は私の答えを更新しました。そして、発生したエラーは、それらのエラーのキーとして' password'フィールド名を含むべきです。 – AKS

+0

部分的( 'PATCH')の更新を行うときに、' ** data'にユーザオブジェクトを作成するために必要なすべてのフィールドが含まれているとは限りません。 – faph

6

あなたはシリアライザオブジェクト上self.instanceを介してユーザオブジェクトにアクセスすることができ、場合でも、フィールドレベルの検証を行います。このようなものが動作するはずです:

from django.contrib.auth import password_validation 

def validate_password(self, value): 
    password_validation.validate_password(value, self.instance) 
    return value 
+0

これは、ユーザーが作成されている場合にのみ使用できます。これは、新しいユーザーを登録し、パスワードの事前作成を検証する場合には当てはまりません。 – tbm

1

シリアライザを使用してください。 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): 
     validated_data = self.check_for_unique_email(validated_data) 
     validated_data.setdefault('username', validated_data['email']) 
     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): 
     validated_data = self.check_for_unique_email(validated_data) 
     user = super().update(instance, validated_data) 
     if 'password' in validated_data: 
      user.set_password(validated_data['password']) 
      user.save() 
     return user 
0

そしてself.instanceはNoneになり、それが あなたは、パスワードの変更をパスワードを休んまたはパスワードでユーザーデータを更新しているときに動作します。あなたのメールアドレスまたはユーザ名と類似してはならない、パスワードを確認したい場合は は、しかし、あなたはあなたのコード内のいくつかのタイプミスがあり

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.") 
関連する問題