[Django] Django Rest Framework Serializer & generic API View
Django Rest Framework Serializer & generic API View
API View
API View
Post - create flow
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
get_serializer는 어떻게 동작하는가.
def get_serializer(self, request, *args, **kwargs):
serializer_class = get_serializer_class()
kwargs['context'] = self.get_serializer_context()
return serializer_class(*args, **kwargs)
def get_serializer_context(self):
"""
Extra context provided to the serializer class.
"""
return {
'request': self.request,
'format': self.format_kwarg,
'view': self
}
def get_serializer_class(self):
assert self.serializer_class is not None()
return self.serializer_class
### BaseSerializer : __init__ 메소드
def __init__(self, instance=None, data=empty, **kwargs):
self.instance = instance
if data is not empty:
self.initial_data = data
self.partial = kwargs.pop('partial', False)
self._context = kwargs.pop('context', {})
kwargs.pop('many', None)
super(BaseSerializer, self).__init__(**kwargs)
- get_serializer(data=request.data) :
- get_serializer_class 메소드를 호출, data=request.data는 kwargs로 포함됨.
- kwargs = {“data”:request.data}에 get_serializer_context() 메소드를 호출.
- kwargs = {“data”: request.data, “context”: {‘request’: self.request, ‘format’: self.format_kwargs, ‘view’: self}
마지막으로 해당 serializer_class(*args, **kwargs)를 리턴해준다.
- get_serializer_class(self) :
- APIView를 상속받은 Custom Serializer에서 정의한 serializer_class를 가져옴. 정의하지 않았을 경우에 오류 띄움
- serializer_class(*args, **kwargs):
- kwargs에는 ‘data’와 ‘context’ 가 들어가 있다.
- BaseSerializer의 init 메소드로 올라가 보면
- data=request.data가 들어가게 되어 self.initial_data = data가 저장된다. 또한 partial은 언제 쓰이는지 아직 잘 모르겠지만 일단 넘어가겠다.
- partial과 context는 kwargs에서 pop되어 제거되고 kwargs는 빈 딕셔너리 형태로 init메소드는 끝난다.
def get_serializer(self, request, *args, **kwargs):
serializer_class = get_serializer_class()
kwargs['context'] = self.get_serializer_context()
return serializer_class(*args, **kwargs)
def get_serializer_context(self):
"""
Extra context provided to the serializer class.
"""
return {
'request': self.request,
'format': self.format_kwarg,
'view': self
}
def get_serializer_class(self):
assert self.serializer_class is not None()
return self.serializer_class
### BaseSerializer : __init__ 메소드
def __init__(self, instance=None, data=empty, **kwargs):
self.instance = instance
if data is not empty:
self.initial_data = data
self.partial = kwargs.pop('partial', False)
self._context = kwargs.pop('context', {})
kwargs.pop('many', None)
super(BaseSerializer, self).__init__(**kwargs)
- get_serializer(data=request.data) :
- get_serializer_class 메소드를 호출, data=request.data는 kwargs로 포함됨.
- kwargs = {“data”:request.data}에 get_serializer_context() 메소드를 호출.
- kwargs = {“data”: request.data, “context”: {‘request’: self.request, ‘format’: self.format_kwargs, ‘view’: self}
마지막으로 해당 serializer_class(*args, **kwargs)를 리턴해준다.
- get_serializer_class(self) :
- APIView를 상속받은 Custom Serializer에서 정의한 serializer_class를 가져옴. 정의하지 않았을 경우에 오류 띄움
- serializer_class(*args, **kwargs):
- kwargs에는 ‘data’와 ‘context’ 가 들어가 있다.
- BaseSerializer의 init 메소드로 올라가 보면
- data=request.data가 들어가게 되어 self.initial_data = data가 저장된다. 또한 partial은 언제 쓰이는지 아직 잘 모르겠지만 일단 넘어가겠다.
- partial과 context는 kwargs에서 pop되어 제거되고 kwargs는 빈 딕셔너리 형태로 init메소드는 끝난다.
Serializer의 is_valid 는 어떻게 동작하는가
def is_valid(self, raise_exception=False):
assert not hasattr(self, 'restore_object'), (
'Serializer `%s.%s` has old-style version 2 `.restore_object()` '
'that is no longer compatible with REST framework 3. '
'Use the new-style `.create()` and `.update()` methods instead.' %
(self.__class__.__module__, self.__class__.__name__)
)
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)
def run_validation(self, data=empty):
"""
Validate a simple representation and return the internal value.
The provided data may be `empty` if no representation was included
in the input.
May raise `SkipField` if the field should not be included in the
validated data.
"""
(is_empty_value, data) = self.validate_empty_values(data)
if is_empty_value:
return data
value = self.to_internal_value(data)
self.run_validators(value)
return value
def validate_empty_values(self, data):
"""
Validate empty values, and either:
* Raise `ValidationError`, indicating invalid data.
* Raise `SkipField`, indicating that the field should be ignored.
* Return (True, data), indicating an empty value that should be
returned without any further validation being applied.
* Return (False, data), indicating a non-empty value, that should
have validation applied as normal.
"""
if self.read_only:
return (True, self.get_default())
if data is empty:
if getattr(self.root, 'partial', False):
raise SkipField()
if self.required:
self.fail('required')
return (True, self.get_default())
if data is None:
if not self.allow_null:
self.fail('null')
return (True, None)
return (False, data)
def to_internal_value(self, data):
"""
Transform the *incoming* primitive data into a native value.
"""
raise NotImplementedError(
'{cls}.to_internal_value() must be implemented.'.format(
cls=self.__class__.__name__
)
)
def run_validators(self, value):
"""
Test the given value against all the validators on the field,
and either raise a `ValidationError` or simply return.
"""
errors = []
for validator in self.validators:
if hasattr(validator, 'set_context'):
validator.set_context(self)
try:
validator(value)
except ValidationError as exc:
# If the validation error contains a mapping of fields to
# errors then simply raise it immediately rather than
# attempting to accumulate a list of errors.
if isinstance(exc.detail, dict):
raise
errors.extend(exc.detail)
except DjangoValidationError as exc:
errors.extend(get_error_detail(exc))
if errors:
raise ValidationError(errors)
-
is_valid(self, raise_exception=False):
- self객체를 받아 _validated_date 속성을 넣어준다. 따라서 이후에 validated_date 를 사용하기 위해서는
is_valid
메소드를 우선 통과해야할것이다.
- self 객체에 restore_object 속성이 없다고 선언한다. 왜 하는지 아직 모르겠다.
- self 객체에 initial_data 속성이 있다고 선언한다. initial_data는 위에서 입력한 request.data가 들어갈 것이다.
- self 객체에 _validated_date 속성이 없는지 확인한다. 속성이 존재한다면 넘어가고, 존재하지 않는다면, self.run_validation(self.initial_data)를 호출해 validation을 진행한다. self._validated_data는 self.run_validation 메소드의 리턴값이 들어간다.
-
run_validation(self, data=empty):
- validation을 수행하는 메소드다.
validate_empty_values(data)
의 도움을 받아 데이터가 빈값인지 확인한다.
- 이 함수는 데이터가 비어있다면 validation을 진행하지 않고,
return data
- 이 함수는 데이터가 들어있다면, validation을 진행한다.
-
validate_empty_values(data) :
- 간단한 메소드다. 데이터가 비었는지 확인만 해준다.
-
to_internal_value(data)
:
- 상당히 흥미로운 메소드다. 메소드 이름은 외부 데이터를 내부 데이터로 바꾼다는 의미같은데. Raise NotImplementedError() 코드 뿐이다. BaseSerializer에서 정의한
to_internal_value
메소드를 오버라이딩하지 않으면 에러를 띄운다는 것인데. 지금까지 사용하면서 오버라이딩한적이 없음에도 is_valid
가 잘 작동했기에 아직 잘 이해되지 않는다.
- 일단 data는 request.data가 빈 값이 아니라면 그대로 입력받아 request.data인데, 메소드 이름으
run_validators(self, value)
:
- 단순히 validation을 수행한다. 다만 따로 지정한 validator가 없을 경우에 기본 validator를 가져오고 그렇지 않을 경우,
def is_valid(self, raise_exception=False):
assert not hasattr(self, 'restore_object'), (
'Serializer `%s.%s` has old-style version 2 `.restore_object()` '
'that is no longer compatible with REST framework 3. '
'Use the new-style `.create()` and `.update()` methods instead.' %
(self.__class__.__module__, self.__class__.__name__)
)
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)
def run_validation(self, data=empty):
"""
Validate a simple representation and return the internal value.
The provided data may be `empty` if no representation was included
in the input.
May raise `SkipField` if the field should not be included in the
validated data.
"""
(is_empty_value, data) = self.validate_empty_values(data)
if is_empty_value:
return data
value = self.to_internal_value(data)
self.run_validators(value)
return value
def validate_empty_values(self, data):
"""
Validate empty values, and either:
* Raise `ValidationError`, indicating invalid data.
* Raise `SkipField`, indicating that the field should be ignored.
* Return (True, data), indicating an empty value that should be
returned without any further validation being applied.
* Return (False, data), indicating a non-empty value, that should
have validation applied as normal.
"""
if self.read_only:
return (True, self.get_default())
if data is empty:
if getattr(self.root, 'partial', False):
raise SkipField()
if self.required:
self.fail('required')
return (True, self.get_default())
if data is None:
if not self.allow_null:
self.fail('null')
return (True, None)
return (False, data)
def to_internal_value(self, data):
"""
Transform the *incoming* primitive data into a native value.
"""
raise NotImplementedError(
'{cls}.to_internal_value() must be implemented.'.format(
cls=self.__class__.__name__
)
)
def run_validators(self, value):
"""
Test the given value against all the validators on the field,
and either raise a `ValidationError` or simply return.
"""
errors = []
for validator in self.validators:
if hasattr(validator, 'set_context'):
validator.set_context(self)
try:
validator(value)
except ValidationError as exc:
# If the validation error contains a mapping of fields to
# errors then simply raise it immediately rather than
# attempting to accumulate a list of errors.
if isinstance(exc.detail, dict):
raise
errors.extend(exc.detail)
except DjangoValidationError as exc:
errors.extend(get_error_detail(exc))
if errors:
raise ValidationError(errors)
is_valid(self, raise_exception=False):
- self객체를 받아 _validated_date 속성을 넣어준다. 따라서 이후에 validated_date 를 사용하기 위해서는
is_valid
메소드를 우선 통과해야할것이다. - self 객체에 restore_object 속성이 없다고 선언한다. 왜 하는지 아직 모르겠다.
- self 객체에 initial_data 속성이 있다고 선언한다. initial_data는 위에서 입력한 request.data가 들어갈 것이다.
- self 객체에 _validated_date 속성이 없는지 확인한다. 속성이 존재한다면 넘어가고, 존재하지 않는다면, self.run_validation(self.initial_data)를 호출해 validation을 진행한다. self._validated_data는 self.run_validation 메소드의 리턴값이 들어간다.
- self객체를 받아 _validated_date 속성을 넣어준다. 따라서 이후에 validated_date 를 사용하기 위해서는
run_validation(self, data=empty):
- validation을 수행하는 메소드다.
validate_empty_values(data)
의 도움을 받아 데이터가 빈값인지 확인한다.- 이 함수는 데이터가 비어있다면 validation을 진행하지 않고,
return data
- 이 함수는 데이터가 들어있다면, validation을 진행한다.
validate_empty_values(data) :
- 간단한 메소드다. 데이터가 비었는지 확인만 해준다.
to_internal_value(data)
:- 상당히 흥미로운 메소드다. 메소드 이름은 외부 데이터를 내부 데이터로 바꾼다는 의미같은데. Raise NotImplementedError() 코드 뿐이다. BaseSerializer에서 정의한
to_internal_value
메소드를 오버라이딩하지 않으면 에러를 띄운다는 것인데. 지금까지 사용하면서 오버라이딩한적이 없음에도is_valid
가 잘 작동했기에 아직 잘 이해되지 않는다. - 일단 data는 request.data가 빈 값이 아니라면 그대로 입력받아 request.data인데, 메소드 이름으
- 상당히 흥미로운 메소드다. 메소드 이름은 외부 데이터를 내부 데이터로 바꾼다는 의미같은데. Raise NotImplementedError() 코드 뿐이다. BaseSerializer에서 정의한
run_validators(self, value)
:- 단순히 validation을 수행한다. 다만 따로 지정한 validator가 없을 경우에 기본 validator를 가져오고 그렇지 않을 경우,
Serializer Save Method
def save(self, **kwargs):
assert not hasattr(self, 'save_object'), (
'Serializer `%s.%s` has old-style version 2 `.save_object()` '
'that is no longer compatible with REST framework 3. '
'Use the new-style `.create()` and `.update()` methods instead.' %
(self.__class__.__module__, self.__class__.__name__)
)
assert hasattr(self, '_errors'), (
'You must call `.is_valid()` before calling `.save()`.'
)
assert not self.errors, (
'You cannot call `.save()` on a serializer with invalid data.'
)
# Guard against incorrect use of `serializer.save(commit=False)`
assert 'commit' not in kwargs, (
"'commit' is not a valid keyword argument to the 'save()' method. "
"If you need to access data before committing to the database then "
"inspect 'serializer.validated_data' instead. "
"You can also pass additional keyword arguments to 'save()' if you "
"need to set extra attributes on the saved model instance. "
"For example: 'serializer.save(owner=request.user)'.'"
)
assert not hasattr(self, '_data'), (
"You cannot call `.save()` after accessing `serializer.data`."
"If you need to access data before committing to the database then "
"inspect 'serializer.validated_data' instead. "
)
validated_data = dict(
list(self.validated_data.items()) +
list(kwargs.items())
)
if self.instance is not None:
self.instance = self.update(self.instance, validated_data)
assert self.instance is not None, (
'`update()` did not return an object instance.'
)
else:
self.instance = self.create(validated_data)
assert self.instance is not None, (
'`create()` did not return an object instance.'
)
- self.validated_date와 kwargs를 합쳐서 validated_data에 저장한다
- self.instance가 있다면 업데이트를 하고 없다면 새로 만들어준다.
def save(self, **kwargs):
assert not hasattr(self, 'save_object'), (
'Serializer `%s.%s` has old-style version 2 `.save_object()` '
'that is no longer compatible with REST framework 3. '
'Use the new-style `.create()` and `.update()` methods instead.' %
(self.__class__.__module__, self.__class__.__name__)
)
assert hasattr(self, '_errors'), (
'You must call `.is_valid()` before calling `.save()`.'
)
assert not self.errors, (
'You cannot call `.save()` on a serializer with invalid data.'
)
# Guard against incorrect use of `serializer.save(commit=False)`
assert 'commit' not in kwargs, (
"'commit' is not a valid keyword argument to the 'save()' method. "
"If you need to access data before committing to the database then "
"inspect 'serializer.validated_data' instead. "
"You can also pass additional keyword arguments to 'save()' if you "
"need to set extra attributes on the saved model instance. "
"For example: 'serializer.save(owner=request.user)'.'"
)
assert not hasattr(self, '_data'), (
"You cannot call `.save()` after accessing `serializer.data`."
"If you need to access data before committing to the database then "
"inspect 'serializer.validated_data' instead. "
)
validated_data = dict(
list(self.validated_data.items()) +
list(kwargs.items())
)
if self.instance is not None:
self.instance = self.update(self.instance, validated_data)
assert self.instance is not None, (
'`update()` did not return an object instance.'
)
else:
self.instance = self.create(validated_data)
assert self.instance is not None, (
'`create()` did not return an object instance.'
)
- self.validated_date와 kwargs를 합쳐서 validated_data에 저장한다
- self.instance가 있다면 업데이트를 하고 없다면 새로 만들어준다.
댓글
댓글 쓰기