2018-06-25 TIL(Form Validation)

Field data

폼과 함께 제출된 데이터가 무엇이든간에 is_valid()를 호출하여 유효성을 검사한다. 만약에 is_valid가 True를 반환하면 form.cleaned_data 딕셔너리에 저장된다.

required가 설정이 되어있으면 이미 유효성 검사가 되어서 전달되어서 필요 없는 경우도 있다.

어쨌든 form으로 데이터를 받을 때는 is_valid를 통해 유효성을 검증하는 것은 필수.

validation

일반적으로 처리중에 데이터에 문제가 있으면 ValidationError생성자에 관련 정보를 전달하여 모든 cleaning 메소드에서 ValidationError를 발생시킬 수 있다.

대부분 유효성 검사는 유효성 검사기를 사용하여 수행할 수 있다. 유효성 검사기는 하나의 인수를 사용하여 잘못된 입력에 대해 ValidationError를 발생시키는 단순한 함수이다.

run_validator() 메소드는 모든 필드의 유효성 검사기를 검색하고 모든 오류를 단일 ValidationError로 집계한다.

Field 하위 클래스의 clean() 메소드는 순서대로 to_python(), validate() 그리고 run validator()를 실행하고 오류가 생기면 ValidationError를 발생시킨다. 한번도 에러가 발생하지 않으면 cleaned_data 사전에 삽입한다.

여기까지 필드차원에서 수행되는 메소드.

다음부터는 폼차원에서 수행되는 메소드이다.

clean_()메소드는 서브클래스에서 호출된다.

특정 필드 속성 클리닝하기

recipiendts 필드에 항상 “fred@example.com” 주소가 포함되도록 하고싶다고 하자. 이는 폼에 대한 유효성 검사이므로 recipients 필드에서 동작하는 클리닝 메소드를 작성한다.

from django import forms

class ContactForm(forms.Form):
    # Everything as before.
    ...

    def clean_recipients(self):
        data = self.cleaned_data['recipients']
        if "fred@example.com" not in data:
            raise forms.ValidationError("You have forgotten about Fred!")

        # Always return a value to use as the new cleaned data, even if
        # this method didn't change it.
        return data

서로 의존하는 필드 클리닝하고 유효성 검사하기

만약에 cc_myself필드가 True여야하고 제목에 “Help”라는 단어가 있어야한다고 유효성을 검사한다치자. 여기서 중요한 것은 한 번에 두개 이상 필드에 유효성 검사를 한다는 것이다. 필드가 아닌 폼의 clean()메소드에 관한 내용이라는 것을 알아야한다. 무언가의 유효성을 검사할 때 필드와 폼의 차이를 명확하게 구분하는 것이 중요하다. 필드는 단일 데이터 포인터고 폼은 필드들의 모임이다.

폼의 clean()메소드가 호출될 때까지 모든 개별 필드 clean()메소드가 실행되어 self.cleaned_data는 지금까지 살아남은 데이터로 채워진다. 따라서 검증하고자 하는 필드가 초기 개별 필드 검사에서 살아남지 못할 수도 있다는 사실을 기억해야한다.

이 과정에서 오류를 보고하는 두 가지 방법이 있다. 아마도 가장 일반적인 방법은 폼의 맨 위에 오류를 표시하는 것이다. 이러한 오류를 만들려면 clean() 메소드에서 ValidationError를 발생시키는 것이다.

에를들면

from django import forms

class ContactForm(forms.Form):
    # Everything as before.
    ...

    def clean(self):
        cleaned_data = super().clean()
        cc_myself = cleaned_data.get("cc_myself")
        subject = cleaned_data.get("subject")

        if cc_myself and subject:
            # Only do something if both fields are valid so far.
            if "help" not in subject:
                raise forms.ValidationError(
                    "Did not send for 'help' in the subject despite "
                    "CC'ing yourself."
                )

이 코드에서 유효성 검사 오류가 발생하면 양식 상단에 문제를 설명하는 오류 메시지가 표시된다.

예제 코드에서 super().clean()을 호출하면 상위 클래스의 유효성 검증 로직이 유지된다. 폼이 clean()메소드에서 cleaned_data사전을 반환하지 않는 다른 것을 상속하는 경우 super()호출결과에 cleaned_data를 지정하지 말고 self.cleaned_data를 대신 사용해라.

def clean(self):
    super().clean()
    cc_myself = self.cleaned_data.get("cc_myself")
    ...

유효성 검사 오류를 보고하는 두 번째 방법은 오류 메시지를 필드 중 하나에 할당하는 것이다. 이번에는 폼 디스플레이의 “subject”와 “cc_myself”행 모두에 오류 메시지를 지정해본다.

from django import forms

class ContactForm(forms.Form):
    # Everything as before.
    ...

    def clean(self):
        cleaned_data = super().clean()
        cc_myself = cleaned_data.get("cc_myself")
        subject = cleaned_data.get("subject")

        if cc_myself and subject and "help" not in subject:
            msg = "Must put 'help' in subject when cc'ing yourself."
            self.add_error('cc_myself', msg)
            self.add_error('subject', msg)

add_error()의 두 번째 인수는 단순한 문자열이거나 ValidationError의 인스턴스가 될 수 있다. add_error()는 cleaned_data에서 자동으로 필드를 제거한다.

Steps of validation

지금부터 설명할 아래의 메소드는 한 번에 한 필드씩 폼의 각 필드에 대해 폼에 정의된 순서대로 실행된다. 이전 메소드에서 오류가 발생했는지 여부에 관계없이 form.clean() 또는 override가 실행된다. Field.clean()메소드가 ValidationError를 발생 시키면 필드 별 클리닝 메소드가 호출되지 않는다. 그러나 나머지 필드의 클리닝은 계속 실행된다.

일반적으로 clean()메소드가 실행되고 처음 세 가지의 유효성 검사(to_python(), vlidate(), run_validators())가 처리된다. 보통 이것들은 커스터마이징할 수 있고 clean()메소드가 실행될 때 커스터마이징 된 메소드들이 실행될 것이다.

  1. 필드의 to_python()메소드

수행하는 작업 : 데이터 유형을 수정하도록 값을 강제 변환하고, 가능하지 않다면 ValidationError를 발생시킨다. 이 메소드는 위젯에서 raw값을 허용하고 변환된 값을 반환한다.

예) FloatField는 데이터를 파이썬 부동 소수점으로 변환한다. 그게 가능하지 않다면 ValidationError를 발생시킴.

HANDLES ERRORS : 오류가 발생할 때 Validation Error를 발생시킴(?)

반환 값 : 변환 된 값을 반환함.

  1. 필드의 validate()메소드

수행하는 작업 : 유효성 검사기에 적합하지 않은 필드별 유효성 검사를 처리함. 데이터 유형을 수정하도록 강요된 값을 취하고 오류가 발생할 때마다 ValidationError를 발생시킴

HANDLES ERRORS : 오류를 발생할 때 ValidationError를 발생시킴.

반환 값 : 이 메소드는 아무것도 돌려주지 않는다. 값을 바꾸지 말아야함.

NOTES : 유효성 검사기에 넣을 수 없는 유효성 검사 논리를 처리하려면 유효성 검사를 재정의해야함.

  1. 필드에서 run_validators() 메소드

수행하는 작업 : 필드의 모든 유효성 검사기를 실행한다.

HANDLES ERRORS : 모든 오류를 단을 ValidationError로 집계한다.

NOTES : 이 메소드를 재정의 할 필요는 없다.

  1. Field 서브 클래스의 clean()메소드.

수행하는 작업 : 이 메소드는 to_python, validate 및 run_validators를 올바른 순서로 실행하고 오류를 전달하는 일을 담당한다.

HANDLES ERRORS : 언제든지 메서드에서 ValidationError를 발생시키면 유효성 검사가 중지되고 해당 오류가 발생한다.

반환 값 : 이 메소드는 clean처리된 데이터를 반환한 다음 폼의 cleaned_data사전에 넣는다.

  1. 폼 서브 클래스의 clean_()메소드 - 여기서 은 양식 필드 속성의 이름으로 대체됨

수행하는 작업 : 이 방법은 특정 속성과 관련있는 필드의 유형과 관련이 없는 특정 clean을 수행한다.

사용 방법 : 이 메소드는 매개 변수를 전달하지 않는다. self.cleaned_data에서 필드의 값을 찾아야하며, 폼에서 제출 된 원래 문자열이 아니라 이 시점에서 파이썬 객체가 될 것임을 기억해야한다. (일반 필드는 clean()메소드를 통해서 이미 클리닝되어 cleaned_data에 있을 것이다)

반환 값 : cleaned_data에서 얻은 정리 된 값

  1. Form 서브 클래스의 clean()메소드.

수행하는 작업 : 이 메소드는 폼의 여러 필드에 한 번에 액세스 해야하는 모든 유효성 검사를 수행할 수 있다.

예 : 필드 A가 제공되면 필드 B는 유효한 이메일 주소등을 포함해야한다.

사용 방법 : clean()이 호출 될 때까지 필드 유효성 검사 메소드가 실행되었으므로 개별 필드의 정리로 발생하는 모든 오류가 포함된 폼의 error속성에도 액세스할 수 있다.

HANDLES ERRORS : Form.clean() 재정의로 발생하는 오류는 특히 어떤 필드와도 관련되지 않는다는 점에 유의해야한다. 필요한 경우 non_field_errors()메소드를 통해 접근할 수 있는 특수한 “필드”(__all__)로 이동한다.폼의 특정 필드에 오류를 첨부하려면 add_error()로 호출해야한다.

반환 값 : 이 메소드는 원하는 경우 완전히 다른 사전을 반환 할 수 있으며 이는 cleaned_data로 사용된다.

NOTES : ModelForm 하위 클래스의 clean()메소드를 재정의 할 때는 특별한 고려 사항이 있다. ModelForm설명을 참조.

Comments