오늘도 개발

[1차 프로젝트 록차] 상품 목록 GET api 제작기 2 - 어떻게 필터링을 구현할까 본문

TIL & 프로젝트 회고

[1차 프로젝트 록차] 상품 목록 GET api 제작기 2 - 어떻게 필터링을 구현할까

Sueeeeeee 2022. 7. 21. 23:59

카테고리를 누르면 상품 목록을 보여주는 페이지로 이동하는데, 

이 때 상품 목록 데이터를 응답하는 api를 만들고 있다.

 

처음에는 요청한 카테고리에 들어있는 전체 상품 데이터를 보내주고

페이지네이션, 필터링은 프론트가 작업하려고 했는데

상품 개수가 많아지는 경우 효율적이지 못한 방식이라는 피드백을 받았다.

 

생각해보니 지금 과제로 만들고 있는 사이트는 카테고리 안에 상품이 많아봐야 20개 정도 들어있지만,

큰 쇼핑몰이었다면 만 개가 넘을 수도 있다.

백엔드에서 먼저 필터링과 페이지네이션을 해서 데이터를 보내주는 방식이

훨씬 효율적이고 확장성 있기 때문에 api를 그에 맞게 설계하기로 했다.

 

고민

1차 카테고리, 2차 카테고리, 1차 필터(신상품, 가격 높은 순, 가격 낮은 순), 2차 필터(티백, 파우더, 잎차), 

그리고 페이지네이션까지 어떻게 한 엔드포인트로 구현할까? 

 

또 1차 카테고리만 클릭한 경우, 2차 카테고리만 클릭한 경우, 1차 필터와 2차 필터를 동시에 클릭한 경우,

아무 필터도 클릭하지 않은 경우 등 가능한 경우의 수가 너무 많은데 어떻게 정리해서 코드로 나타낼 수 있을까?

 

접근 방법

우선 가능한 경우와 엔드포인트를 글로 정리해보고,

프론트 담당자와 이야기 나눠볼 수 있도록 정리한 내용을 트렐로에 공유했다. 

정리 결과는 다음과 같다.

1. 디폴트 설정 

- 상품은 24개씩만 보여줌
- 신상품순으로 보여줌
- 티 제품인 경우 전체 타입으로 보여줌

 쿼리 파라미터가 없는 경우 디폴트
'티 제품' 카테고리에 속한 상품 전체를 보여줌.

 /products/list


2. 카테고리를 선택한 경우

1) 1차 카테고리를 선택한 경우 디폴트
1차 카테고리 아이디를 쿼리 파라미터에 입력해서 요청하면
해당 카테고리에 속한 상품 전체를 보여줌

 /products/list?first-category=1

2) 2차 카테고리를 선택한 경우 디폴트
2차 카테고리 아이디를 쿼리 파라미터에 입력해서 요청하면
해당 카테고리에 속한 상품 전체를 보여줌

 /products/list?second-category=1


3. 필터 선택한 경우

1) 1차 필터를 선택한 경우
키는 sort이고 값은 new-arrival, price-desc, price-asc 중 선택

 /products/list?sort=new-arrival

2) 2차 필터를 선택한 경우
키는 type이고 값은 tealeaf, pyramid, teabag, powder 중 선택

/products/list?type=tealeaf


4. 카테고리, 1차 필터, 2차 필터를 섞어서 사용한 경우

1) 카테고리를 선택하고 1차 필터와 2차 필터를 선택한 경우

/products/list?category=teashop&sort=price-desc&type=teabag

2) 여러 타입을 선택한 경우(티 제품인 경우)

/products/list?type=tealeaf,pyramid

 

5. 페이지를 선택한 경우

디폴트로 한 번에 제품을 10개씩만 보여주기.

예를 들어 제품을 10개씩 보여주는 경우 두 번째 페이지를 요청하려면 다음과 같이 작성.

/products/list?limit=10&offset=2

 

실마리

1. 쿼리 파라미터로 받은 키와 값은 장고에서 request.GET으로 접근할 수 있다.

request.GET은 QueryDict라는 오브젝트인데, 딕셔너리처럼 사용할 수 있다.

 

예를 들어 요청을 이렇게 보낸 경우,

(1차 카테고리 아이디 3, 2차 카테고리 아이디 1, 타입이 tealeaf과 powder인 모든 제품을 가격 높은순으로 정렬해서 보내달라는 요청

/products/list?first-category=3&second-category=1&sort=desc&type=tealeaf,powder

views.py에서 request.GET을 찍어보면 다음과 같이 나온다. 

print(request.GET)
# <QueryDict: {'first-category': ['3'], 'second-category': ['1'], 'sort': ['desc'], 'type': ['tealeaf, powder']}>

 

 

2. 딕셔너리의 키로 값을 불러올 때 get을 쓰면 존재하지 않는 키를 사용해도 오류가 나지 않는다.

딕셔너리에 없는 키를 부르면 오류가 나는데 어떻게 request.GET을 사용할까 고민하다 get 메서드를 발견했다.

get 메서드를 사용해서 키를 찾는 경우, 딕셔너리에 키가 존재하지 않으면 None을 반환한다.

(None 말고 다른 디폴트 값을 넣을 수도 있다.)

print(request.GET)
# <QueryDict: {}>

print(request.GET.get('first_category', None))
# None

즉, 다음과 같이 if 문을 사용해서 쿼리 파라미터가 있는지 확인할 수 있을 것이다.

if request.GET.get('first-category', None):
	pass

3. Q 오브젝트를 사용하면 동적으로 쿼리를 생성하고 조합할 수 있다.

 

그렇다면 위에서 글로 정리한 내용을 코드로 작성해보면 되지 않을까?

(다음화에 계속)