본문 바로가기
DEV/Web 개발

Web개발 :: Code Review _ Review CRUD 기능 _TIL80

by 올커 2022. 12. 28.

■ JITHub 개발일지 80일차

□  TIL(Today I Learned) ::

Code Review _ Review CRUD 기능

Review CRUD

#models.py
from django.core.validators import MaxValueValidator, validate_image_file_extension #validators=[validate_image_file_extension]이미지형식이 아닐때 막아줌

class Review(models.Model):
    content = models.TextField('내용', max_length=500)
    review_image_one = models.ImageField('이미지 1', upload_to='review_pics', blank=True, validators=[validate_image_file_extension])#validators=[validate_image_file_extension]이미지형식이 아닐때 막아줌 ex) 음성파일
    review_image_two = models.ImageField('이미지 2', upload_to='review_pics', blank=True, validators=[validate_image_file_extension])
    review_image_three = models.ImageField('이미지 3', upload_to='review_pics', blank=True, validators=[validate_image_file_extension])
    created_at = models.DateTimeField('후기 생성 시간', auto_now_add=True)
    updated_at = models.DateTimeField('후기 수정 시간', auto_now=True)
    rating_cnt = models.PositiveIntegerField('별점', validators=[MaxValueValidator(5)]) #PositiveIntegerField사용으로 음수가 없는 IntegerField설정, 최대 5점까지 줄 수 있게 해줌
    
    review_like = models.ManyToManyField(User, verbose_name='후기 좋아요', related_name="like_review", blank=True)

    author = models.ForeignKey(User, verbose_name='작성자', on_delete=models.CASCADE)
    place = models.ForeignKey(Place, verbose_name='장소', on_delete=models.CASCADE, related_name="place_review")#장소 id를 사용하기 위해서 가져옴

    class Meta:
        db_table = 'review'

    def __str__(self):
        return f'[작성자]{self.author}, [내용]{self.content}'

ReviewListView

#urls.py

urlpatterns = [
	path('<int:place_id>/', views.ReviewListView.as_view(), name='review_list_view'),
	path('<int:review_id>/likes/',views.ReviewLikeView.as_view(), name='review_like_view'),
]

# 장소 리뷰 리스트

#views.py

class ReviewListView(APIView):
	#장소 리뷰 리스트
	def get(self, request, place_id):
	
	        #최신순
	        recent_review = Review.objects.filter(place_id=place_id).order_by('-created_at')
					recent_review_serializer = ReviewListSerializer(recent_review, many=True).data
	
	        #좋아요순
	        like_count_review = Review.objects.filter(place_id=place_id).annotate(num_likes=Count('review_like')).order_by('-num_likes','-created_at')
	        like_count_review_serializer = ReviewListSerializer(like_count_review, many=True).data
	
	        review = {
	            "recent_review": recent_review_serializer,
	            "like_count_review": like_count_review_serializer
	        }
	        return Response(review, status=status.HTTP_200_OK)

📌좋아요순 추가 설명 : https://www.notion.so/2084680dad8d454b9d4e51765c8f3810

 

좋아요 카운트 순으로 리뷰 정렬 할 때 오류

에러 발생 이유

www.notion.so

#serializers.py

# 후기 전체 serializer
class ReviewListSerializer(serializers.ModelSerializer):
    nickname = serializers.SerializerMethodField() #새롭게 추가하고 싶은 필드를 시리얼라이저에 추가
    profile_image = serializers.SerializerMethodField()
    place_name = serializers.SerializerMethodField()
    review_like_count = serializers.SerializerMethodField()
    place = PlaceSerializer() #placeserializer 가져와서 사용

    def get_nickname(self, obj):#정참조 ForeignKey로 연결된 모델을 사용할때 가져오는 방법
																 #get_이름 이런식으로 작성
																 #nickname = serializers.SerializerMethodField() 세트로 사용
        return obj.author.user_profile.nickname

    def get_profile_image(self, obj):
        return obj.author.user_profile.profile_image.url

    def get_place_name(self, obj):
        return obj.place.place_name

    def get_review_like_count(self, obj):
        return obj.review_like.count()

    class Meta:
        model = Review
        fields = ('content', 'review_image_one', 'created_at', 'updated_at', 'rating_cnt', 'review_like_count', 'review_like', 'author_id' , 'nickname', 'profile_image', 'place_name', 'id', 'author_id', 'place_id', 'place',)

#리뷰 작성

#views.py

class ReviewListView(APIView):
	#리뷰 작성
  def post(self, request, place_id):
      profile = get_object_or_404(Profile, user=request.user)
      serializer = ReviewCreateSerializer(data=request.data, context={"place_id":place_id, "request":request})
      if serializer.is_valid():
          profile.review_count_add
          serializer.save(author=request.user, place_id=place_id)
          return Response(serializer.data, status=status.HTTP_201_CREATED)
      return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#serializers.py

class ReviewCreateSerializer(serializers.ModelSerializer):
  class Meta:
      model = Review
      fields = ('content', 'rating_cnt', 'review_image_one', 'review_image_two', 'review_image_three', )
      extra_kwargs = {'content':{
                      'error_messages': {
                      'required':'내용을 입력해주세요.',
                      'blank':'내용을 입력해주세요.',}},
                      
                      'rating_cnt':{
                      'error_messages':{
                      'required':'평점을 입력해주세요',
                      'blank':'평점을 입력해주세요',}},}

ReviewDetailView

#urls.py

urlpatterns = [
	path('details/<int:place_id>/<int:review_id>/',views.ReviewDetailView.as_view(), name='review_detail_view'),
]

#리뷰 상세 페이지

#views.py

class ReviewDetailView(APIView):
	def get(self, request, place_id, review_id):
        review = get_object_or_404(Review, id=review_id)
        serializer = ReviewDetailSerializer(review)
        return Response(serializer.data, status=status.HTTP_200_OK)
#serializers.py

# 후기 상세페이지 serializer
class ReviewDetailSerializer(serializers.ModelSerializer):
    nickname = serializers.SerializerMethodField()
    profile_image = serializers.SerializerMethodField()
    place_name = serializers.SerializerMethodField()
    review_like_count = serializers.SerializerMethodField()
    review_comments = CommentSerializer(many=True) #댓글이 여러개니깐 many=True

    def get_nickname(self, obj): #정참조 ForeignKey로 연결된 모델을 사용할때 가져오는 방법
																 #get_이름 이런식으로 작성
																 #nickname = serializers.SerializerMethodField() 세트로 사용
        return obj.author.user_profile.nickname

    def get_profile_image(self, obj):
        return obj.author.user_profile.profile_image.url

    def get_place_name(self, obj):
        return obj.place.place_name
        
    def get_review_like_count(self, obj):
        return obj.review_like.count()

    class Meta:
        model = Review
        fields = ('content', 'author_id', 'review_image_one', 'review_image_two', 'review_image_three', 'created_at', 'updated_at', 'rating_cnt', 'review_like', 'review_like_count', 'nickname', 'profile_image', 'place_name', 'review_comments', )

#리뷰 수정

#views.py

#리뷰 수정
class ReviewDetailView(APIView):
    def put(self, request, place_id, review_id):
        review = get_object_or_404(Review, id=review_id)
        if request.user == review.author:
            serializer = ReviewCreateSerializer(review, data=request.data, partial=True, context={"place_id":place_id, "review_id":review_id, "request":request})
            #partial=True 부분수정
						# place_id, review_id 사용하기위해서 context 담아서 serializer로 넘겨준다.
						if serializer.is_valid():
                serializer.save(author=request.user, review_id=review_id)
                return Response(serializer.data, status=status.HTTP_200_OK)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        return Response({"message":"접근 권한 없음"}, status=status.HTTP_403_FORBIDDEN)

#리뷰 삭제

#views.py

class ReviewDetailView(APIView):
	def delete(self, request, place_id, review_id):
        review = get_object_or_404(Review, id=review_id)
        place = get_object_or_404(Place, id=place_id)
        profile = get_object_or_404(Profile, user=request.user)
        if request.user == review.author:
            profile.review_count_remove
            review_cnt = place.place_review.count() #리뷰의 총개수
            if review_cnt == 1:
                place.rating = 0
            else:
                place.rating = (place.rating * review_cnt - review.rating_cnt) / (review_cnt - 1)#리뷰에대한 별점을 반영시키기 위한 계산, 리뷰한개를 뺀 별점평균
            place.save()
            review.delete()
            return Response({"message":"리뷰 삭제"}, status=status.HTTP_200_OK)
        return Response({"message":"접근 권한 없음"}, status=status.HTTP_403_FORBIDDEN)

 

 

 

반응형

댓글