티스토리 뷰
이전 Serializer 포스팅에서 Serializer를 만들 때 필드를 각각 설정했었다. models.py 에서 정의한 모델의 attibute를 다시 반복해서 설정해주는 느낌이 들어서 불편한 점이 있었다. BaseSerializer를 쓴다고 해서 문제가 되지는 않지만 우리는 편리함을 추구하는 개발자이기 때문에! ModelSerializer를 알아보자.
joeylee.log님의 게시글을 참고하였습니다.
ModelSerializer는 크게 3가지의 기능을 제공한다.
1. 의존하고 있는 모델에 기반해서 Serializer 필드를 자동으로 생성
2. Serializer를 위한 validator 제공
3. Create, Update 함수를 기본으로 제공
아래 코드는 ModelSerializer 클래스에서 제공하는 create, update 함수이다.
def create(self, validated_data):
raise_errors_on_nested_writes('create', self, validated_data)
ModelClass = self.Meta.model
# Remove many-to-many relationships from validated_data.
# They are not valid arguments to the default `.create()` method,
# as they require that the instance has already been saved.
info = model_meta.get_field_info(ModelClass)
many_to_many = {}
for field_name, relation_info in info.relations.items():
if relation_info.to_many and (field_name in validated_data):
many_to_many[field_name] = validated_data.pop(field_name)
try:
instance = ModelClass._default_manager.create(**validated_data)
except TypeError:
tb = traceback.format_exc()
msg = (
'Got a `TypeError` when calling `%s.%s.create()`. '
'This may be because you have a writable field on the '
'serializer class that is not a valid argument to '
'`%s.%s.create()`. You may need to make the field '
'read-only, or override the %s.create() method to handle '
'this correctly.\nOriginal exception was:\n %s' %
(
ModelClass.__name__,
ModelClass._default_manager.name,
ModelClass.__name__,
ModelClass._default_manager.name,
self.__class__.__name__,
tb
)
)
raise TypeError(msg)
# Save many-to-many relationships after the instance is created.
if many_to_many:
for field_name, value in many_to_many.items():
field = getattr(instance, field_name)
field.set(value)
return instance
def update(self, instance, validated_data):
raise_errors_on_nested_writes('update', self, validated_data)
info = model_meta.get_field_info(instance)
# Simply set each attribute on the instance, and then save it.
# Note that unlike `.create()` we don't need to treat many-to-many
# relationships as being a special case. During updates we already
# have an instance pk for the relationships to be associated with.
m2m_fields = []
for attr, value in validated_data.items():
if attr in info.relations and info.relations[attr].to_many:
m2m_fields.append((attr, value))
else:
setattr(instance, attr, value)
instance.save()
# Note that many-to-many fields are set after updating instance.
# Setting m2m fields triggers signals which could potentially change
# updated instance and we do not want it to collide with .update()
for attr, value in m2m_fields:
field = getattr(instance, attr)
field.set(value)
return instance
ModelSerialize 사용 방법
1) class Meta 작성
- model = 해당하는 모델 명
- fields = '__all__' (default)
- read_only_field
2) serializer로 정의해주는 필드
- 사용자가 ModelSerializer에 추가하고 싶은 필드가 있는 경우 serializer.SerializerMethod()로 정의
- 외래키로 연결된 필드가 있는 경우, 디폴드는 연결된 필드의 pk를 가져옴
- 만약 해당 데이터의 pk가 아닌 String이나 Hyperlink를 가져오고 싶으면 별도로 지정해야함
Nested Relationship
앞서 언급했듯 외래키 필드를 사용하고자 할 때, 기본적으로 아무런 조건이 없다면 참조하고 있는 pk 값을 가져온다.
만약 pk값 이외에 다른 값을 가져오고 싶으면 다음과 같이 정의할 수 있다.
1) String of related object
- 외래키로 연결된 모델의 __str__ 메소드에서 정의한 문자열을 리턴한다.
- 인자로 many=True, read-only=True 등을 가질 수 있음
class ArticleSerializer(serializers.ModelSerializer):
author = serializers.StringRelatedField()
2) All information of related object
- 참조할 모델의 Serializer를 가져와서 사용 (참조할 Serializer가 더 위에 위치해야 참조할 수 있음)
- 인자로 many=True, read_only=True 등을 가질 수 있음
- Journalist <- Article이 참조하는 관계(1:N) 로서 ArticleSerializer에서 author를 참조할 수 있다.
- 반대로 JournalistSerializer에서 articles를 참조할 수 있다.
class JournalistSerializer(serializers.ModelSerializer):
# articles = ArticleSerializer(many=True, read_only=True)
class ArticleSerializer(serializers.ModelSerializer):
author = JounarlistSerializer(read_only=True)
3) Links of related object
- HyperLinkRelatedField는 외래키로 연결된 타켓 필드의 API url을 리턴한다.
- many, read_only, view_name 등을 지정해줘야 한다.
[serializers.py]
class JournalistSerializer(serializers.ModelSerializer):
articles = serializers.HyperlinkedRelatedField(many=True,read_only=True, view_name="article-detail")
[views.py]
class JournalistListCreateAPIView(APIView):
def get(self, request):
journalists = Jounalist.object.all()
serializer = JounalistSerializer(journalists, many=True,context={'request':request})
return Response(serializer.data)
GET /api/journalists/ 요청이 들어오면 "127.0.0.1:8000/api/articles/1/" 이런 방식으로 리턴된다
'Django' 카테고리의 다른 글
[Django] Cookie SameSite 이슈 (0) | 2022.02.04 |
---|---|
[Django] User Authenticate / 유저 인증 (0) | 2022.01.30 |
[Django] Django View (Class-based view, Function-based view) (0) | 2022.01.17 |
[Django] Django Serializers (0) | 2022.01.16 |
[Django] DRF - Django Rest Framework (0) | 2022.01.11 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 스프링 프레임워크
- Spring
- java
- 8주차 회고
- 회고
- 런칭 페스티벌
- 우테코 회고
- 2차 데모데이
- 팀프로젝트
- 피움
- 파이썬
- 스프링MVC
- 알림기능개선기
- 3차 데모데이
- 알림개선기
- 5주차 회고
- ZNS SSD
- 우테코
- dm-zoned
- dm-zoned 코드분석
- 프로젝트
- jpa
- 환경 별 로깅 전략 분리
- 피움 6주차 회고
- 스프링 Logback
- ZNS
- 백준
- CI/CD
- 스프링 부트
- 네트워크
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
글 보관함