django에서 API 등을 만들다 보면 serializer는 필수불가결한 존재이다. 사용하다보면 validate를 재정의해서 사용하기도 하고 validate_{field_name}, to_representation 등을 재정의해서 사용하곤 한다.
그런데 serializer의 각 메소드들은 언제 호출되고 어떤 용도로 사용되는 걸까?
먼저 create, update와 같이 입력 데이터를 검증하고 처리하는 경우에는 다음과 같다.
시리얼라이저 객체가 생성되고 나서 가장 먼저 호출하는 함수는 is_valid이다.
def is_valid(self, *, raise_exception=False):
# This implementation is the same as the default,
# except that we use lists, rather than dicts, as the empty case.
assert hasattr(self, 'initial_data'), (
'Cannot call `.is_valid()` as no `data=` keyword argument was '
'passed when instantiating the serializer instance.'
)
if not hasattr(self, '_validated_data'):
try:
self._validated_data = self.run_validation(self.initial_data)
except ValidationError as exc:
self._validated_data = []
self._errors = exc.detail
else:
self._errors = []
if self._errors and raise_exception:
raise ValidationError(self.errors)
return not bool(self._errors)
내부 구조는 다음과 같으며 _validated_data가 존재하지 않을 시 즉, validation이 수행되지 않았으면 initial_data를 기준으로 run_validation를 수행한다.
def run_validation(self, data=empty):
...
value = self.to_internal_value(data)
try:
self.run_validators(value)
value = self.validate(value)
assert value is not None, '.validate() should return the validated data'
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=as_serializer_error(exc))
return value
def to_internal_value(self, data):
...
for field in fields:
validate_method = getattr(self, 'validate_' + field.field_name, None)
primitive_value = field.get_value(data)
try:
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = get_error_detail(exc)
except SkipField:
pass
else:
set_value(ret, field.source_attrs, validated_value)
if errors:
raise ValidationError(errors)
return ret
위의 코드에서 tointernal_value가 수행되며 각 필드에 대해서 run_validation을 수행하고 만약 시리얼라이저에 validate{field_name}이 정의되어 있을 경우 이를 수행하고 에러 발생시 errors에 담는다.
이때 각 필드의 run_validation 호출 시 run_validator가 호출되며 각 필드에 정의된 validator를 수행한다.
이 과정이 끝나면 run_validation 마지막에 validate가 호출되고 모든 검증, 변형이 끝난 결과값이 반환되고 이를 validated_data에서 확인할 수 있다.
클라이언트에서 받은 데이터를 필드로 변환하는 작업을 수행한다.
특정 필드에 대해서만 검증을 수행할때 정의해서 사용한다. 정의된 validator가 수행되고 호출된다.
대부분의 과정이 끝나고 마지막에 수행되는 검증 함수이다. 객체 전체에 대한 검증이나 여러 필드가 상호작용할 때의 검증 시 사용한다.
data(property 함수) 호출 시 호출되는 함수로 출력 시점에 데이터를 가공할 때 사용한다.
save 함수 호출시 인스턴스의 여부, 즉 생성인지 업데이트인지에 따라서 create, update가 각각 호출된다.
일반 시리얼라이저엔 create, update가 정의되어 있지 않고 ModelSerailizer에는 정의되어 있다
data 호출 시 initial_data, _validated_data로 현재 단순 직렬화인지, 생성, 수정인지 파악 후 둘다 없을 경우 단순 직렬화로 판단하고 둘다 존재할 경우 is_valid가 끝난 상태로 파악한다. 만약 _validated_data만 없는 경우 is_valid를 먼저 하라는 에러를 발생시킨다.