Django Form 소스 분석의 BaseForm 검증 논리
Django에서 Form의 주요 기능은 입력 검증과 템플릿에서의 전시로 나뉜다.먼저 Form의 소스 정의를 살펴보겠습니다.
class Form(six.with_metaclass(DeclarativeFieldsMetaclass, BaseForm)):
"A collection of Fields, plus their associated data."
# This is a separate class from BaseForm in order to abstract the way
# self.fields is specified. This class (Form) is the one that does the
# fancy metaclass stuff purely for the semantic sugar -- it allows one
# to define a form using declarative syntax.
# BaseForm itself has no way of designating self.fields.
BaseForm의 검증 논리 분석과 관련된 것이기 때문에 저는 본 블로그에서fields에 있는 데이터를 요청에서 어떻게 얻는지 관심이 없습니다. 저는 데이터가 처리를 거쳐fields에 전달되었다고 가정합니다.(템플릿의 출력 형식 규범도 많이 언급하지 않음) 그리고 저는 인용문에서 BaseForm의 초기화를 제시하여 찾아보기 쉽도록 하겠습니다.
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, error_class=ErrorList, label_suffix=None,
empty_permitted=False, field_order=None):
self.is_bound = data is not None or files is not None
self.data = data or {}
self.files = files or {}
self.auto_id = auto_id
if prefix is not None:
self.prefix = prefix
self.initial = initial or {}
self.error_class = error_class
# Translators: This is the default suffix added to form field labels
self.label_suffix = label_suffix if label_suffix is not None else _(':')
self.empty_permitted = empty_permitted
self._errors = None # Stores the errors after clean() has been called.
# The base_fields class attribute is the *class-wide* definition of
# fields. Because a particular *instance* of the class might want to
# alter self.fields, we create self.fields here by copying base_fields.
# Instances should always modify self.fields; they should not modify
# self.base_fields.
self.fields = copy.deepcopy(self.base_fields)
self._bound_fields_cache = {}
self.order_fields(self.field_order if field_order is None else field_order)
양식 데이터 바인딩:Form.is_bound
바인딩 논리 판정은 초기화에서 다음과 같습니다.
self.is_bound = data is not None or files is not None
이것은 다음과 같은 상황을 잘 설명한다.
>>> not_bound = exampleForm()
>>> not_bound.is_bound
False
>>> is_bound = exampleForm({})
>>> is_bound.is_bound
True
일반적으로 데이터 매개 변수는 Request입니다.POST or request.GET, files 매개변수는 request.FILES, 주의해야 할 것은 파일을 업로드할 때 Request를 요구합니다.method는 POST이고 enctype='multipart/form-data'여야 합니다.
양식의 유효성 검사 방법: Form.is_valid()
def is_valid(self):
""" Returns True if the form has no errors. Otherwise, False. If errors are being ignored, returns False. """
return self.is_bound and not self.errors
먼저 양식 데이터가 바인딩된 후에야 유효성을 검사할 수 있으며 양식이 유효성 검사 과정에서 raise Validation Error가 없을 때 True로 돌아갑니다.is_bound 속성은 내가 방금 이미 분석했기 때문에self를 중점적으로 본다.errors 속성입니다.
Form.errors
초기화에서 우리는 전혀 self가 없다는 것을 볼 수 있다.errors 이 속성은self.errors라는 개인 속성입니다.python에서 @property 사용법을 사용했기 때문입니다.
@property
def errors(self):
"Returns an ErrorDict for the data provided for the form"
if self._errors is None:
self.full_clean()
return self._errors
우리가 처음으로 form을 호출할 때is_valid () 또는 form에 액세스합니다.errors 속성이 있을 때self를 호출합니다.full_clean () 함수, 이외에 사유의self.errors. 기본적으로 form.errors는 필드를 키로 하고value는Validation Error 메시지를 포함하는 Error List의 사전입니다. 물론 우리가 필요로 하는 것은 메시지가 아니라 진정한Validation Error 실례일 수도 있습니다. 이때form을 호출할 수 있습니다.errors.as_데이터 (), 이외에form도 제공합니다.errors.as_json().(이 두 가지 방법은 다음 문장에서 출처를 언급할 것이다)
Form.full_clean()
fullclean ()에서 주로self. 호출됨clean_fields(),self._clean_form(),self._post_clean()은 폼에 대한 검증을 완성했다. 그 중에서 우리는 구체적인 필드에 대한 분석을 하지 않고 폼 전체의 검증을 중점적으로 분석한다.(즉, self. clean form()
def full_clean(self):
""" Cleans all of self.data and populates self._errors and self.cleaned_data. """
self._errors = ErrorDict()
if not self.is_bound: # Stop further processing.
return
self.cleaned_data = {}
# If the form is permitted to be empty, and none of the form data has
# changed from the initial data, short circuit any validation.
if self.empty_permitted and not self.has_changed():
return
self._clean_fields()
self._clean_form()
self._post_clean()
Form에서.full_clean () 방법에서 우리는 errors 속성이 실제로는 ErrorDict라는 것을 볼 수 있다. 우리는 위에서 언급한form을 간단하게 분석한다.errors.as_data().
Form.errors.as_data()
# ErrorDict.as_data()
def as_data(self):
return {f: e.as_data() for f, e in self.items()}
위에서 언급한value는 ErrorList입니다.
# ErrorList.as_data()
def as_data(self):
return ValidationError(self.data).error_list
여기서 ValidationError.error_list는 ValidationError 인스턴스가 포함된 list입니다.
Form._clean_form()
def _clean_form(self):
try:
cleaned_data = self.clean()
except ValidationError as e:
self.add_error(None, e)
else:
if cleaned_data is not None:
self.cleaned_data = cleaned_data
그 중에서 clean 함수는form에서 제공하는 개발자가 스스로 정의할 수 있는 함수로 원시적인 정의에서 간단히self를 되돌려준다.cleaned_data.우리는 clean 함수를 덮어쓰고 전체 폼 차원의 검증 논리 사용자 정의를 제공할 수 있습니다. 이때self.cleaned_데이터는field의 필드 검증을 거쳤습니다.
def clean(self):
""" Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named '__all__'. """
return self.cleaned_data
그래서 form에서.clean ()에서 발생하는 모든 이상은self에 저장됩니다.errors에서 키는 입니다.all__의value에서 주의해야 할 것은 우리가Form을 직접 통과할 수 있다는 것이다.non_field_errors() 반환all__의 ErrorList를 참조하십시오. 이유all__자, 우리 다음으로self를 분석합시다.add_error 함수.
Form.add_error(field, error)
그 중에서 error는 문자열일 수도 있고,ValidationError의 실례일 수도 있습니다.
def add_error(self, field, error):
"""
Update the content of `self._errors`. The `field` argument is the name of the field to which the errors should be added. If its value is None the errors will be treated as NON_FIELD_ERRORS. The `error` argument can be a single error, a list of errors, or a dictionary that maps field names to lists of errors. What we define as an "error" can be either a simple string or an instance of ValidationError with its message attribute set and what we define as list or dictionary can be an actual `list` or `dict` or an instance of ValidationError with its `error_list` or `error_dict` attribute set. If `error` is a dictionary, the `field` argument *must* be None and errors will be added to the fields that correspond to the keys of the dictionary. """ if not isinstance(error, ValidationError): # Normalize to ValidationError and let its constructor # do the hard work of making sense of the input. error = ValidationError(error) if hasattr(error, 'error_dict'): if field is not None: raise TypeError( "The argument `field` must be `None` when the `error` " "argument contains errors for multiple fields." ) else: error = error.error_dict else: error = {field or NON_FIELD_ERRORS: error.error_list} for field, error_list in error.items(): if field not in self.errors: if field != NON_FIELD_ERRORS and field not in self.fields: raise ValueError( "'%s' has no field named '%s'." % (self.__class__.__name__, field)) if field == NON_FIELD_ERRORS: self._errors[field] = self.error_class(error_class='nonfield') else: self._errors[field] = self.error_class() self._errors[field].extend(error_list) if field in self.cleaned_data: del self.cleaned_data[field]
def _clean_fields(self):
for name, field in self.fields.items():
# value_from_datadict() gets the data from the data dictionaries.
# Each widget type knows how to retrieve its own data, because some
# widgets split data over several HTML fields.
if field.disabled:
value = self.initial.get(name, field.initial)
처음에 나는Form이라고 생각했습니다.initial 이 속성은 데이터로 초기화된 매개 변수이지만, 나중에 생각해 보니 그렇지 않다. 단지 Field일 뿐이다.disabled를 사용할 때form은 initial에서 값을 가져옵니다. 이 인자는 전시용으로 사용되며 데이터의 기본값이 아닙니다.주의, 여기Form.initial은ModelForm과 구분하여django-forms-default-values-for-bound-forms를 참고해야 합니다.또한 Django 공식 문서에는 다음이 설명되어 있습니다.These values are only displayed for unbound forms, and they’re not used as fallback values if a particular value isn’t provided.
마지막으로 나는 다시 한 가지 예를 제시한다.
class QueryForm(forms.Form): limit = forms.IntegerField(required=False) offset = forms.IntegerField(required=False)
>>> f = QueryForm(data={}, initial={'limit': 20, 'offset': 0})
>>> f.is_bound
True
>>> f.is_valid()
True
>>> f.cleaned_data
{'limit': None, 'offset': None}
다음에 나는 다른 블로그에서 Field에 대한 원본 분석을 전개할 것이다.부족한 점이 있으면 삼가 가르침을 바랍니다.이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Asp와 XML로 상호작용하는 실례 원본XML은 표준 확장 언어로 미래 웹 프로그래밍의 표준이다. asp는 현재 널리 전해지는 웹 프로그래밍 언어 중의 하나이다. 그들 두 사람이 연합하여 역할을 발휘할 수 있을까?두부는 여기서 여러분에게 아주 간단한 As...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.