본문으로 바로가기
  • 리뷰 api user 앱으로 옮겨야할까? 지금 url 하나의 요청으로 필요한 정보 모아서 보내주는중
  • 유저들고오는 메소드, 리뷰만 가져오는 메소드 따로 한다면 옮겨야 할까?
  • 서버에 부담이 되는정도의 양은 아닐것이다 그럼 쿼리를 최대한 줄이고 restful하게 유저에서 하나의 api에서 가져오는게 맞을까?
  • 일단 지금은 필요한 데이터만 딱 들고오게끔 생각해서 리팩토링 해보자
  • 속도 측정 할 것
  • 결과적으로 유저 프로필은 user에서 만든 api로 불러오고 리뷰는 리뷰api불러오고 필요한 부분만 딱딱 불러오고 옥션같은데서 유저만 불러와야할 때도 분리해서 사용할 수 있게 만들자
  • 쿼리수를 줄이기 x 쿼리를 최적화해서 시간을 줄이기 o

코드를 리팩토링 할 시간이 조금은 생겨서 쿼리를 줄이는 방법을 공부하고 어떻게 내 코드를 고쳐볼까 고민했다

첫번째는 팀원인 준호님이 도움을 주셔서 filter를 한번만 사용해서 다 가져오고 for문으로 개수를 계산을해서 넘겨주면 좋겠다고 팁을 주셔서 고쳐보려고했다

 

도중에 생각난건 최악의 상황을 생각해야 하는 것이며 쿼리를 줄이고 양을 많이 들고오는것이 생각났고 쿼리는 좀 많지만 양을적게 들고오는것 두개의 장점을 합쳐서 딱 필요한 만큼의 쿼리로 내가 필요한 정보만 들고와서 내가 데이터를 조작해서 보내는게 중요하다. 라는 것이다.

이야기 하면서 필터는 서버에 부하가 가는것이고 서비스 페이지에 들고오면서 부하되는건 컴퓨터라는걸 이제서야 좀 이해 했다. 이 부분은 조금더 공부를 할 예정이다

 

두번째는 필요한 쿼리만 딱 보내고 모든걸 한번에 넘겨주고 싶었다.

# review_list=Review.objects.filter(receiver_id=user_id).select_related('score')
# review_list_order_by = review_list.order_by('-created_at')
# serializer=ReviewListSerializer(review_list_order_by, many=True)

# bad_review_count = receiver.filter(score=-20).count()
# soso_review_count = receiver.filter(score=0).count()
# good_review_count = receiver.filter(score=3).count()
# excellent_review_count = receiver.filter(score=5).count()
# receiver_serializer=UserSerializer(receiver)

# image=[]
# for review in receiver:
# author=UserSerializer(review.author).data['profile_image']
# image.append(author)

# data = {
# "bad_review_count":bad_review_count,
# "soso_review_count":soso_review_count,
# "good_review_count":good_review_count,
# "excellent_review_count":excellent_review_count,
# "results":serializer.data,
# "receiver":receiver_serializer.data,
# "review_image":image
# }
 
원래의 코드
class UserInfoAPIView(APIView):
    # permission_classes = [permissions.IsAuthenticated]
    def get(self, request, user_id):
        
        """
        판매자 정보에 들어갔을때 후기모음
        """
        review_list=Review.objects.filter(receiver_id=user_id)
        review_list_order_by = review_list.order_by('-created_at')
        serializer=ReviewListSerializer(review_list_order_by, many=True)

        bad_review_count = review_list.filter(score=-20).count()
        soso_review_count = review_list.filter(score=0).count()
        good_review_count = review_list.filter(score=3).count()
        excellent_review_count = review_list.filter(score=5).count()

        receiver=User.objects.get(id=user_id)
        receiver_serializer=UserSerializer(receiver)

        image=[]
        for review in review_list_order_by:
            author=UserSerializer(review.author).data['profile_image']
            image.append(author)

        data = {
            "bad_review_count":bad_review_count,
            "soso_review_count":soso_review_count,
            "good_review_count":good_review_count,
            "excellent_review_count":excellent_review_count,
            "results":serializer.data,
            "receiver":receiver_serializer.data,
            "review_image":image
        }

        return Response(data, status=status.HTTP_200_OK)

여기서 공부한걸 활용해서

        reviews=Review.objects.filter(receiver_id=user_id).prefetch_related('receiver')
        data=[{
            "score":review.score,
            "username":review.receiver.username,
            # "profile_image":review.receiver.profile_image
        }for review in reviews]
        return Response({'result':data})

데이터를 받아오는데 성공

        reviews=Review.objects.filter(receiver_id=user_id).prefetch_related('receiver')
        reviews2=Review.objects.filter(receiver_id=user_id)
        print(reviews)
        print("2",reviews2)
        serializer=ReviewCreateSerializer(reviews, many=True)
        serializer2=ReviewCreateSerializer2(reviews2, many=True)
        print("1",serializer.data)
        print("2",serializer2.data)

        print("요기는 모에요?",reviews[0].score)

시리얼라이저 형태와 데이터를 어떻게 사용하는지 찍어보면서 복습!

        reviews=Review.objects.filter(receiver_id=user_id).prefetch_related('receiver')
        reviews3=Review.objects.filter(receiver_id=user_id).prefetch_related('receiver', 'author')
        reviews2=Review.objects.filter(receiver_id=user_id)
        print(reviews)
        print("2",reviews2)
        serializer=ReviewCreateSerializer(reviews, many=True)
        serializer2=ReviewCreateSerializer2(reviews2, many=True)
        serializer3=ReviewCreateSerializer2(reviews3, many=True)
        print("1",serializer.data)
        print("2",serializer2.data)
        print("3",serializer3.data)
        for i in reviews:
            print ("for 안",i.receiver.id)
        print("요기는 모에요?",reviews[0].score)
        image=[{
            UserSerializer(review.receiver).data['profile_image']
        } for review in reviews ]
        # for i in reviews
        print(image)
        image2=[]
        for review in reviews2:
            author=UserSerializer(review.author).data['profile_image']
            image2.append(author)
        print("이미지2",image2)
        data={"data":[{
            "content":review.content,
            "username":review.author.username,
            "created_at":review.created_at,
            # "profile_image":review.receiver.profile_image
        }for review in reviews],

        
        "안녕":'안녕',
        "img":image
        # "username":reviews[3].receiver.username
        }
        return Response({'result':data})

들고온 이미지들 userserializer에 넣어서 리스트에 추가해서 보내준다. 아니면 에러발생

[{'/media/media/%E1%84%87%E1%85%A1%E1%84%83%E1%85%A5%E1%86%A8_%E1%84%8B%E1%85%A9%E1%84%90%E1%85%A9%E1%84%87%E1%85%A1%E1%84%8B%E1%85%B5_%E1%84%8C%E1%85%A5%E1%86%BC%E1%84%89%E1%85%A1%E1%84%80%E1%85%A1%E1%86%A8%E1%84%92%E1%85%A7%E1%86%BC.png'}, {'/media/media/%E1%84%87%E1%85%A1%E1%84%83%E1%85%A5%E1%86%A8_%E1%84%8B%E1%85%A9%E1%84%90%E1%85%A9%E1%84%87%E1%85%A1%E1%84%8B%E1%85%B5_%E1%84%8C%E1%85%A5%E1%86%BC%E1%84%89%E1%85%A1%E1%84%80%E1%85%A1%E1%86%A8%E1%84%92%E1%85%A7%E1%86%BC.png'}]
이미지2 ['/media/media/%E1%84%92%E1%85%A9%E1%86%AF%E1%84%84%E1%85%A1%E1%86%A8%E1%84%8C%E1%85%A5%E1%86%BD%E1%84%8B%E1%85%B3%E1%86%AB_%E1%84%80%E1%85%B5%E1%86%B7%E1%84%87%E1%85%A1%E1%84%83%E1%85%A5%E1%86%A8.png', '/media/media/%E1%84%92%E1%85%A9%E1%86%AF%E1%84%84%E1%85%A1%E1%86%A8%E1%84%8C%E1%85%A5%E1%86%BD%E1%84%8B%E1%85%B3%E1%86%AB_%E1%84%80%E1%85%B5%E1%86%B7%E1%84%87%E1%85%A1%E1%84%83%E1%85%A5%E1%86%A8.png']

image 와 image2 의 비교 같게 만들어줌

이제 매너평가 개수 어떻게 나타낼지 보자

우선은 리뷰를 먼저 들고와서 리시버를 가져온다면 리뷰없으면 리시버 정보를 못들고오는게 맞다.

유저를 나타내는 메소드만 다르게하고 댓글만 따로 불러오기 하거나( 그럼 리시버의 사진이나 유저네임을 같은메소드에서 요청하지않는다)

진짜 쿼리 하나로 끝내려면 user에서 시작해서 들고와야하고 필터해서 리뷰에 리시버가 리시버 아이디 인것만 들고와서 author 의 아이디와 사진 리뷰의 컨텐트 들고와야한다. 

쿼리 개수를 줄이면 다 되는줄알고 줄일려고 노력했다 결국 한개가 줄고 불필요한 filter count를 없앴다

하지만 중요한건 최적화를 잘하는 것인걸 공부하면서 알았다 나중에 데이터접근이 중복될때 속도를 측정해서 줄여볼 수 있을 것 같다. 

의미있는 공부였다.