1.drf 팀프로젝트 - serializer update(), ininstance
문제점
serializer를 이용해서 데이터 베이스의 정보를 업데이트 해야함
시도해 본 것들
drf 공식문서 찾아보기
update()함수 찾기
def update(self, instance, validated_data):
"""
Update and return an existing `Snippet` instance, given the validated data.
"""
instance.title = validated_data.get('title', instance.title)
instance.code = validated_data.get('code', instance.code)
instance.linenos = validated_data.get('linenos', instance.linenos)
instance.language = validated_data.get('language', instance.language)
instance.style = validated_data.get('style', instance.style)
instance.save()
return instance
개인 프로젝트 때 create()함수만 사용해보고 update()는 사용해본 적이 없었는데 이번 기회에 알아봤다.
update()함수 파고들어가기
def update(self, instance, validated_data):
raise_errors_on_nested_writes('update', self, validated_data)
info = model_meta.get_field_info(instance)
raise_errors_on_nested_writes라는 함수 확인하기
def raise_errors_on_nested_writes(method_name, serializer, validated_data):
ModelClass = serializer.Meta.model
model_field_info = model_meta.get_field_info(ModelClass)
# Ensure we don't have a writable nested field. For example:
#
# class UserSerializer(ModelSerializer):
# ...
# profile = ProfileSerializer()
assert not any(
isinstance(field, BaseSerializer) and
(field.source in validated_data) and
(field.source in model_field_info.relations) and
isinstance(validated_data[field.source], (list, dict))
for field in serializer._writable_fields
), (
'The `.{method_name}()` method does not support writable nested '
'fields by default.\nWrite an explicit `.{method_name}()` method for '
'serializer `{module}.{class_name}`, or set `read_only=True` on '
'nested serializer fields.'.format(
method_name=method_name,
module=serializer.__class__.__module__,
class_name=serializer.__class__.__name__
)
)
여기서 instance는 아니지만 isinstance라는 함수가 보였다. 우선 assert은 모르지만 not any는 하나라도 False라면 밑의 메시지가 띄워지는 것 같다.
isinstance확인하기
def isinstance(__obj: object, __class_or_tuple: _ClassInfo) -> bool: ...
def issubclass(__cls: type, __class_or_tuple: _ClassInfo) -> bool: ...
def len(__obj: Sized) -> int: ...
def license() -> None: ...
def locals() -> dict[str, Any]: ...
class map(Iterator[_S], Generic[_S]):
무슨 말인지 하나도 모르겠지만 len과 map이 눈에 띄었다. 그래서 파일을 살펴보니 python의 내장 함수 파일이었다.
isinstance가 내장 함수라면 설명이 있을 것이라 판단하고 찾아봤다.
isinstance검색하기
print(isinstance(1234, int)) # True
print(isinstance("1234", int)) # False
isinstance는 주어진 변수의 타입을 True, False로 반환해주는 함수였다.
raise_errors_on_nested_writes함수 코드 다시 살펴보기
isinstance(field, BaseSerializer)
이렇게 떼어놓고 보니 간단하다.
field가 BaseSerializer의 type과 일치하는지 확인한다.
save()함수 찾아보기
def save(self, **kwargs):
"""
Save and return a list of object instances.
"""
# 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)'.'"
)
validated_data = [
{**attrs, **kwargs} for attrs in self.validated_data
]
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.'
)
return self.instance
대부분 무슨소린지 모르겠지만 if문은 눈에 들어왔다.
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.instance가 있다면 update가 실행되고, 없다면 create가 실행 되는 것으로 보인다. 그래서 궁금했던 내가 view에서 사용하는 것은 save()인데 create()와 update()가 알아서 구분되는 구조를 알 수 있었다.
가장 궁금했던 instance는 찾지 못했지만 print()를 통해서 확인한 결과 db의 값이 그대로 나오는 것을 알 수 있었고, create()와 update()의 차이를 알게 되면서 이해할 수 있었다.
다만 print(instance)를 했을 때는 email이 나오고 있었는데 지금 그 원인을 알게 된 것 같다.
BaseUserManger 를 사용하면서 기본적으로 email을 사용하고 그 값이 unique값이므로 instance가 이메일을 가르키고 있던 것 같다.
알게 된 점
serializer의 save()가 create()와 update()를 구분하는 기준을 알 수 있었다.
serializer의 update()함수에 전달되는 instance라는 변수가 db의 값을 받아오는 것을 알 수 있었다.
isinstance라는 파이썬 내장함수의 사용법을 알 수 있었다.
아직도 모르는게 더 많지만 조금이라도 아는 부분을 기준으로 이해를 넓일 수 있는 경험을 할 수 있었다.
실제로 코드를 사용하기 위해서 찾아보면 확실히 더 많은 노력을 기울일 수 있는 것을 지금 프로젝트를 하면서 느꼈다.
'개발일지 > TIL' 카테고리의 다른 글
TIL 23-05-14 drf 팀 프로젝트 - git rebase squash (0) | 2023.05.14 |
---|---|
TIL 23-05-13 drf 팀 프로젝트 - 프론트에서 이미지 보내기 (0) | 2023.05.13 |
TIL 23-05-11 drf 팀 프로젝트 - git - PR후 작업, push취소, branch명 변경, commit내용 변경 (0) | 2023.05.11 |
TIL 23-05-10 drf 팀 프로젝트 - 이메일 인증 (0) | 2023.05.11 |
TIL-23-05-09 drf 팀 프로젝트 - validation (0) | 2023.05.09 |