기존에 만든 View는 모델링을 합쳐서 약 이틀에 걸쳐 만든 결과물이었고,
프론트 엔드분들에게 보여주기 위해 30분만에 만들기는 했지만, DB 접속 횟수를 줄여 효율성을 높이기 위해 나름대로 리팩토링도 했다.
그러나 결국 갈아엎게 되었는데, 이전의 코드와 이후의 코드를 비교해보고자 한다.
# 카테고리, 메뉴이름, 조리시간, 몇인분인지, 좋아요 개수
class ListByCategory(View) :
def get(self,request,category_id) :
data = Products.objects.select_related('category').filter(category_id=category_id)
product_lists = []
for i in data :
product_lists.append(i.id)
# 좋아요 테이블에서, 우리가 보여줄 목록에 있는 상품이 들어있는 모든 좋아요 데이터를 가져와서 Counter 사용
likes = list(Like.objects.filter(product_id__in=product_lists).values_list())
likes_list = Counter([x[1] for x in likes])
like_boolean = []
# AccessToken이 있는 경우에, Like 테이블에서 해당 사용자가 좋아요를 누른 상품 리스트를 찾음.
if 'Authorization' in request.headers :
user_id = get_user_id(self,request)
like_boolean = [x[2] for x in list(Like.objects.filter(user_id =user_id, product_id__in=product_lists).values_list())]
result = []
for i in data :
result.append({
"id" : i.id,
"category" : i.category.name,
"name" : i.name,
"like" : likes_list[i.id],
"this_user_like": int(i.id in like_boolean),
}
)
return JsonResponse({
"result" : result
})
# 제품명, 조리시간, 몇인분인지, 카테고리, 좋아요 개수, 해시태그
class DetailByProduct(View) :
def get(self,request,product_id) :
# product 테이블의 ID를 foreignKEY로 사용하는 테이블들을 한번에 가져오기 위해 prefetch_realated사용
products = Products.objects.select_related('category'
).prefetch_related('product_main_images','products_hashtag', 'product_detail_attrs'
).get(id=product_id) #1
likes = Like.objects.filter(product_id=product_id).count()
hash_numbers = [x[0] for x in list(products.products_hashtag.values_list('hashtag_id'))]
detail = [{
"text" : i.text,
"image_url" : i.image_url,
"priority" : i.priority,
} for i in products.product_detail_attrs.filter(product_id=product_id)]
hash_names = [x[0] for x in list(Hashtags.objects.filter(id__in=hash_numbers).values_list('name'))]
result = {
"image" : products.product_main_images.values("main_image_url").get(product_id=product_id)["main_image_url"],
"category" : products.category.name, #1
"name" : products.name,
"likes" : likes,
"hashtag" : hash_names
}
return JsonResponse({
"result" : [result],
"detail" : detail
})
# 카테고리 기준으로 상품리스트 반환하는것과 거의 동일하지만, 카테고리 기준이 아닌 좋아요가 높은 숫자의 상품을 반환하도록 되어 있음.
class ListByLike(View) :
def get(self,request,*args) :
# 좋아요에서 가장 숫자가 높은 친구들 찾기.
likes = [x["product_id"] for x in list(Like.objects.all().values('product_id'))]
top6 = [x[0] for x in sorted(list(Counter(likes).items()), key=lambda x : x[1], reverse=True)[:6]]
likes_lists = [x[1] for x in sorted(list(Counter(likes).items()), key=lambda x : x[1], reverse=True)[:6]]
product_lists = Products.objects.filter(id__in =top6)
idx = 0
like_boolean = []
if 'Authorization' in request.headers :
user_id = get_user_id(self,request)
like_boolean = [x[2] for x in list(Like.objects.filter(user_id =user_id, product_id__in=product_lists).values_list())]
result = []
for i in product_lists :
result.append({
"id" : i.id,
"mainImage" : i.thumbnail_out_url,
"subImage" : i.thumbnail_over_url,
"category" : i.category.name,
"name" : i.name,
"cookingTime" : i.cook_time,
"serving" : i.servings_g_people,
"like" : likes_lists[idx],
"this_user_like": int(i.id in like_boolean)
}
)
idx+=1
return JsonResponse({
"result" : result
})
내가 스스로 생각했던 문제점은 이렇다.
1. 분명히 상품 리스트(카테고리), 상품 리스트(좋아요), 상품 상세페이지에는 서로 겹치는 내용이 있음에도 불구하고, 기능별로 구분해서 함수화를 못한 상태이다.
2. select_related()와 prefetched_related()를 사용하기는 했는데, 정확히 어떤식으로 효율이 좋아지는지 알지 못한 상태로 코드를 작성했다.
3. URL Path Parameter로 INPUT으로 들어오는 데이터의 유형이 달랐다. 따라서 변수명이 다르고,
코드의 흐름이 달랐기 때문에 코드를 합치기에 문제가 있었다.
멘토님에게 받은 피드백은 지향점은 같지만 전혀 새로운 방법을 제시해주는 것 이었다.
클래스를 하나로 합치라. 백엔드는 Input/Output 에 따라 코드를 작성하는 것이 아닌, 데이터의 흐름에 따라 코드를 작성해야 한다.
이 피드백을 듣고, 조금이라도 좋은 코드를 만들기 위해 클래스를 하나로 합치게 되었다.