조회수는 간단하게 구현하려고 하면 게시글 상세보기 요청할때마다 +1 하는 방식으로 간단하게 구현 가능하지만, 이런 방식은 한명이 조회수를 여러번 올리는 행위가 가능하다.
그렇기 때문에 쿠키나 IP 등을 활용하여 중복 조회 방지를 통해 좀 더 유사한 조회수를 구현할 수 있다.
여기서는 쿠키를 활용했다.
# articles/views.py
class Article_ViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all().order_by('-pk')
serializer_class = ArticleSerializer
permission_classes = [IsOwnerOrReadOnly]
pagination_class = Article_pagination
def list(self, request):
qs = self.get_queryset()
page = self.paginate_queryset(qs)
if page is not None:
serializer = self.get_paginated_response(self.get_serializer(page, many=True).data)
else:
serializer = self.get_serializer(page, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
def perform_create(self, serializer):
serializer.save(
user=self.request.user,
)
def retrieve(self, request, pk=None):
instance = get_object_or_404(self.get_queryset(), pk=pk)
# 당일날 밤 12시에 쿠키 초기화
tomorrow = datetime.datetime.replace(timezone.datetime.now(), hour=23, minute=59, second=0)
expires = datetime.datetime.strftime(tomorrow, "%a, %d-%b-%Y %H:%M:%S GMT")
# response를 미리 받고 쿠키를 만들어야 한다
serializer = self.get_serializer(instance)
response = Response(serializer.data, status=status.HTTP_200_OK)
# 쿠키 읽기 & 생성
if request.COOKIES.get('hit') is not None: # 쿠키에 hit 값이 이미 있을 경우
cookies = request.COOKIES.get('hit')
cookies_list = cookies.split('|') # '|'는 다르게 설정 가능 ex) '.'
if str(pk) not in cookies_list:
response.set_cookie('hit', cookies+f'|{pk}', expires=expires) # 쿠키 생성
instance.hits += 1
instance.save()
else: # 쿠키에 hit 값이 없을 경우(즉 현재 보는 게시글이 첫 게시글임)
response.set_cookie('hit', pk, expires=expires)
instance.hits += 1
instance.save()
# hits가 추가되면 해당 instance를 serializer에 표시
serializer = self.get_serializer(instance)
return response
Article의 viewset 에서 retrieve를 오버라이딩 해준다.
hit라는 쿠키에 내가 조회한 게시글의 pk가 담기는 것을 확인할 수 있다.