てっくらふと

IT技術系ブログ。たまにV系もあるかも : JetpackCompose / Django / FastAPI

DjangoのValidationErrorのエラーメッセージ一覧を出力したい時、[error.message for error in ValidationError.error_list]を使うとハマるかもしれない話

こんにちは。うぃんちゃんです。
DjangoでValidationErrorのエラーメッセージを出力したい時に「ValidationError.error_list」を使うと、エラーメッセージがフォーマットされずハマる可能性があります。

結論

error変数をValidationError型とすると、

[inner_error_message for inner_error_message in error]

でOK。

どのような時にハマるか

[error.message for error in ValidationError.error_list]

のように書いた時、エラーメッセージがフォーマットされずに出力されてしまいます。

具体例を挙げると、Djangoのパスワードバリデーションが正しいかどうか次のviewを書いたとします。

@api_view(['POST'])
def validate_password(request):
    if 'password' not in request.data:
        return Response(status=400)

    try:
        password_validation.validate_password(request.data['password'])
        return JsonResponse({
            'result': True
        })
    except ValidationError as error:
        return JsonResponse({
            'result': False,
            'error_messages': [error.message for error in error.error_list]
        })

すると、最低文字数のエラーメッセージがフォーマットされずに次のように表示されてしまいます。

このパスワードは短すぎます。最低 %(min_length)d 文字以上必要です。

原因

本来、ValidationErrorをループで回すと__iter__関数により次の処理が走って正しい文字列にフォーマットされてくれます。

    def __iter__(self):
        if hasattr(self, 'error_dict'):
            for field, errors in self.error_dict.items():
                yield field, list(ValidationError(errors))
        else:
            for error in self.error_list:
                message = error.message
                if error.params:
                    message %= error.params # ここでフォーマットされてくれる
                yield str(message)

しかし、error_listからerrorを直接持ってきてmessageを取り出してしまうとフォーマットされません。

対策

冒頭に書いたとおり、

[inner_error for inner_error in error]

でOKです。
errorをループで回すと勝手に文字列にフォーマットされてエラー一覧の文字列の配列になります。

CSS Design created by satotaka99. Thankyou.