こんにちは。うぃんちゃんです。
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をループで回すと勝手に文字列にフォーマットされてエラー一覧の文字列の配列になります。