■ 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
#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)
반응형
'DEV > Web 개발' 카테고리의 다른 글
Web개발 :: 프로젝트 정리 및 회고 _TIL82 (0) | 2022.12.29 |
---|---|
Web개발 :: Code 기능 리뷰(검색), Deploy _TIL81 (1) | 2022.12.28 |
Web개발 :: Code Review _ Place 추천 기능 _TIL79 (0) | 2022.12.28 |
Web개발 :: Code Review _ User 관리 기능 _TIL78 (0) | 2022.12.28 |
Web 개발 :: 12월 넷째주 WIL17 (0) | 2022.12.28 |
댓글