https://github.com/sdoram/b4_exhibitions_backend
1. serializer를 복수 선언하기
장점 : 필요한 경우의 수 만큼 선언하면 간단하게 해결 가능
단점 : 필요한 종류에 따라서 serializer를 계속 선언하면 하나의 기능을 위한 수많은 serializer 생성 가능성 존재
결론 : 최초 구현시 간단하게 쓸만한 느낌이지만, 최종적으로 사용하기엔 아쉬운 방법이다
2. to_representation() 사용
https://www.django-rest-framework.org/api-guide/serializers/#creating-new-base-classes
장점 : views에서 코드 가독성 증가
단점 : 사용법 이해 부족, 코드를 이해하지 못하면 역으로 가독성 저하
결론: 사용법을 익히는데 시간 소요가 있지만, 결과적으로 더 효율적인 코드 사용 가능
1.to_representation 사용하기
문제점
view에서 조건에 따라 다른 field를 불러와야 하는 상황 발생
시도해 본 것들
https://sdoram.tistory.com/183
# views.py
def get(self, request, exhibition_id):
exhibition = get_object_or_404(Exhibition, id=exhibition_id)
# query_params를 serializer로 전달
serializer = ExhibitionDetailSerializer(
exhibition, context={"select": request.query_params.get("select", None)}
)
context에 query_parmas 정보 담아서 보내기
ExhibitionDetailSerializer(serializers.ModelSerializer):
"""전시회 상세보기"""
select = serializers.SerializerMethodField()
# query_params에 따라서 필드 변경
if select == "accompanies":
accompanies = AccompanySerializer(many=True)
else:
reviews = ReviewSerializer(source="review_set", many=True
select가 serializer if문에서는 None으로 분기 처리가 안됨
ExhibitionDetailSerializer(serializers.ModelSerializer):
"""전시회 상세보기"""
accompanies = AccompanySerializer(many=True)
reviews = ReviewSerializer(source="review_set", many=True)
# 읽기 전용 직렬화
# serializer.data에서 select가 안된 다른 필드 값을 ''으로 변경
def to_representation(self, instance):
# serializer.data
data = super().to_representation(instance)
# query_params
select = self.context["select"]
# 데이터 값 빈값으로 교체
if select == "accompanies":
data["reviews"] = ""
else:
data["accompanies"] = ""
return data
class Meta:
model = Exhibition
필요한 필드를 모두 가져온 뒤 읽기를 위한 to_representation안에서 select값 사용하기
결과만 보면 어느정도 바라던 결과를 볼 수 있지만, 모든 데이터를 불러오고 필요없는 데이터를 공백으로 만들어서 보여주는 과정이 비효율적으로 느껴짐
해결 방법
def to_representation(self, instance):
# serializer.data
data = super().to_representation(instance)
# query_params
select = self.context["select"]
# select에 따라 filed 추가
if select == "accompanies":
accompany = instance.accompanies.all()
serializer = AccompanySerializer(accompany, many=True)
data["accompanies"] = serializer.data
else:
# related_name 설정 필요
reviews = instance.review_set.all()
serializer = ReviewSerializer(reviews, many=True)
data["reviews"] = serializer.data
return data
sererializer를 to_representation 내에서 선언하도록 변경
이 과정에서 ForeignKey로 참조하는 과정에서 related_name이 선언된 필드와 아닌 필드 존재
알게 된 점
related_name이 무엇인지는 알고 있지만, 보통 전혀 안쓰거나, 모두 쓰거나 해서 크게 체감할 일이 없었는데 이번에 이 코드를 구현하며 정확하게 느낄 수 있었다.
2. serializer내부 pagination 사용
문제점
하나의 게시글을 조회하고 그 게시글에 붙는 글의 페이지네이션이 필요함
시도해 본 것들
get_paginated_response() 알아보기
def get_paginated_response(self, data):
return Response(OrderedDict([
('count', self.page.paginator.count),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
('results', data)
]))
serializer에서 사용하려 했지만 에러 발생 pagination.py에 선언된 method 찾아보기
return Response라서 발생하는 에러로 추측
class CustomPageNumberPagination(PageNumberPagination):
PAGE_SIZE = 9
def get_paginated_response(self, data):
return OrderedDict(
[
("count", self.page.paginator.count),
("next", self.get_next_link()),
("previous", self.get_previous_link()),
("results", data),
]
)
CustomPageNumberPagination으로 오버라이딩
해결 방법
def to_representation(self, instance):
# serializer.data
data = super().to_representation(instance)
pagination = CustomPageNumberPagination()
# query_params
select = self.context["select"]
# select에 따라 field 추가
if select == "accompanies":
accompany = instance.accompanies.all()
paginated_accompanies = pagination.paginate_queryset(
accompany, self.context["request"]
)
serializer = AccompanySerializer(paginated_accompanies, many=True)
data["accompanies"] = pagination.get_paginated_response(serializer.data)
else:
# related_name 설정 필요
reviews = instance.review_set.all()
paginated_reviews = pagination.paginate_queryset(
reviews, self.context["request"]
)
serializer = ReviewSerializer(paginated_reviews, many=True)
data["reviews"] = pagination.get_paginated_response(serializer.data)
데이터에
OrderedDict(
[
("count", self.page.paginator.count),
("next", self.get_next_link()),
("previous", self.get_previous_link()),
("results", data),
]
)
OrderedDict에 담아서 전달
알게 된 점
레퍼런스가 없어도 시간을 들여서 사용해보면서 얻는 정보들이 유의미하다.
Collections 모듈에 포함되어 있는 OrderedDict는 순서까지 정해진 dict의 형태다.
'프로젝트 > 미술관 뒤 백엔드 지금은 전시상황' 카테고리의 다른 글
최종 팀 프로젝트[front] API function 분리하기 (0) | 2023.06.14 |
---|---|
최종 팀 프로젝트[back] 통합 검색 filter (1) | 2023.06.13 |
최종 팀 프로젝트[front] navbar (0) | 2023.06.09 |
최종 팀 프로젝트[back] drf_pagination (0) | 2023.06.08 |
최종 팀 프로젝트 S.A. (0) | 2023.06.05 |