1차 Project - 2

Jina·2020년 5월 4일
0

Project

목록 보기
3/7

Step 4. View 만들기

car/views.py

우리가 car app에서 구현하고 싶어하는 내용은 아래와 같다.

  • 자동차 종류별로 option default 값 보내기
  • 자동차 종류별로 option의 가능한 조합 보내기
  • 선택한 옵션이 적용된 Image url 보내기
  • 선택한 옵션 요약 page에 보내기
  • 내 차량 정보 저장하기
  • 내 차량 정보 불러오기

shopping/views.py

우리가 shopping app에서 구현하고 싶어하는 내용은 아래와 같다.

  • 시승신청 user 정보 저장하기
  • 시승신청 table에 리스트 보내기

기록하고 싶은 view

위의 기능 구현 중 몇개의 view를 기록해보려고 한다.

default 값 보내기

각 자동차의 종류(model, version, line) 마다 option 선택의 default값이 달랐다.
따라서 이 default 값을 먼저 frontend에게 보내주는 view가 필요했다.

작성한 view는 아래와 같다.

 class DefaultView(View):
     def get(self,request,mvl_id):
         default_info = Default.objects.select_related('exterior_type','wheel_type','caliper_type','seat_type','dashboard_type','carpet_type','steering_type').filter(model_version_line_id=mvl_id)

         default_list = [
         {
             'exterior'   : {'color_id' : default.exterior_type.color.id,  'color' : default.exterior_type.color.name ,  'thumbnail_url' : default.exterior_type.thumbnail_url},
             'wheel'      : {'wheel_id' : default.wheel_type.id,           'name'  : default.wheel_type.name,            'thumbnail_url' : default.wheel_type.thumbnail_url},
             'caliper'    : {'color_id' : default.caliper_type.color.id,   'color' : default.caliper_type.color.name,    'thumbnail_url' : default.caliper_type.thumbnail_url},
             'seat'       : {'color_id' : default.seat_type.color.id,      'color' : default.seat_type.color.name,       'thumbnail_url' : default.seat_type.thumbnail_url},
             'dashboard'  : {'color_id' : default.dashboard_type.color.id, 'color' : default.dashboard_type.color.name,  'thumbnail_url' : default.dashboard_type.thumbnail_url},
             'carpet'     : {'color_id' : default.carpet_type.color.id,    'color' : default.carpet_type.color.name,     'thumbnail_url' : default.carpet_type.thumbnail_url},
             'steering'   : {'color_id' : default.steering_type.color.id,  'color' : default.steering_type.color.name,   'thumbnail_url' : default.steering_type.thumbnail_url}}
             for default  in default_info]

         return JsonResponse({'data':default_list},status=200)

여러개의 데이터를 가져와야하기 때문에 select_related를 이용하였다.

가능한 option 보내기

가능한 option은 exterior, wheel, seat등 각각의 옵션에 따라 다른 view를 작성하여 frontend에 보내주었다.

이 중에서 제일 고민했던 view는 carpet과 steering 관련 view이다.
이 두가지 옵션은 seat와 dashboard의 옵션 값에 영향을 받았기 때문에 그 내용을 포함하여 보내주어야했다.
특히 고민했던 부분은 어떤 형식으로 보내주어야 하는가였다.

처음에 생각했던 방식은 아래의 예시와 같이 카테고리별로 구분해서 보내주는 방식이었다.

seat.id : 
	{ dashboard.id : 
    		{ "carpet_id": carpet.id,
            	  "carpet_color" : carpet.color
                  ... }
	}

옵션이 무슨 값인지 알기 쉽다는 장점이 있고, frontend에서 해당 값을 가지고 오려면 딕셔너리 안으로 너무 여러번 접근해야한다는 단점 1과 view 작성시 코드가 복잡해진다는 단점 2가 있었다.

처음 작성했던 코드는 아래와 같다.


  • 처음 코드
class CarpetView(View):
    def get(self,request,mvl_id):
    	# 1
        possible_seat = Seat.objects.prefetch_related('dashboard_set').filter(model_version_line_id=mvl_id)
    	# 2
 	carpet_list   = [
             		   {seat.id :
               			{dashboard.id : list(dashboard.carpet_set.values('id','carpet_type__color','carpet_type__color__name','carpet_type__thumbnail_url'))for dashboard in Dashboard.objects.prefetch_related('carpet_set').filter(seat_id=seat.id)}} for seat in possible_seat
         		 ]

1) possible_seat = Seat.objects.prefetch_related('dashboard_set').filter(model_version_line_id=mvl_id)

request.body로 들어오는 값은 mvl_id 이다.
mvl_id를 통해서 가능한 seat를 알기위해서 위의 내용을 입력하였다.
이 때 prefetch_related를 이용하여 dashboard의 조합도 미리 쿼리했다.
dashboard는 역참조 관계이기 때문에 뒤에 _set을 써주었다.

2) for문 이용하기

2-1) {seat.id : {}} for seat in possible_seat

seat의 id는 seat.id를 이용하여 가져왔다.
for문을 이용하여 시트의 조합들을 차례로 가져왔다.

2-2) {dashboard.id : ~~ for dashboard in Dashboard.objects.prefetch_related('carpet_set').filter(seat_id=seat.id)}

seat.id에 따른 dashboard.id를 가져오기 위하여 위와 같이 코드를 만들었다.
위와 같이 prefetch_related를 이용하여 carpet의 조합도 미리 쿼리했다.
carpet은 역참조 관계이기 때문에 뒤에 _set을 써주었다.

2-3) list(dashboard.carpet_set.values('id','carpet_type__color','carpet_type__color__name','carpet_type__thumbnail_url')) for dashboard in Dashboard.objects.prefetch_related('carpet_set').filter(seat_id=seat.id)

각 dashboard에 따른 carpet의 id, color.id, color.name. thumbnail_url을 가지고 오는 코드이다.

역참조 관계이기 때문에 dashboard.carpet_set을 이용했다.


위의 코드는 가독성이 떨어지는 문제가 있어서 위의 코드 내용을 수정했다.
수정 사항은 아래와 같다.

  • 중간 코드
 class CarpetView(View):
     def get(self,request,mvl_id):
         carpet_list = [
             {	
             	 # 1 
                 "seat_id":seat.id,
                 "dashboard":[
                     {
                         # 2
                         "id": dashboard.id,
                         "carpet": [
                             {
                             	# 3
                                 "id": carpet.id,
                                 "color_id"  : carpet.carpet_type.color.id,
                                 "color_name": carpet.carpet_type.color.name,
                                 "thumbnail_url": carpet.carpet_type.thumbnail_url
                             }for carpet in dashboard.carpet_set.select_related('carpet_type','carpet_type__color').filter(dashboard_id = dashboard.id)]
                	}for dashboard in seat.dashboard_set.filter(seat_id=seat.id)]
             }for seat in Seat.objects.prefetch_related('dashboard_set').filter(model_version_line_id=mvl_id)]

1) seat 관련 for문

   {	
	"seat_id":seat.id,
	"dashboard":[ . . . ]	
    } for seat in Seat.objects.prefetch_related('dashboard_set').filter(model_version_line_id=mvl_id)

Seat.objects.prefetch_related('dashboard_set') : dashboard를 미리 쿼리해두었다. 역참조 관계이기 때문에 dashboard_set을 썼다.
model_version_line_id에 따른 seat를 가져오기 위해서 filter를 이용했다.

2) dashboard 관련 for문

 “dashboard":[
 		{
		   "id": dashboard.id,
		   "carpet": [ ]
		} for dashboard in seat.dashboard_set.filter(seat_id=seat.id)]

seat에 따른 dashboard를 가져오기 위한 for문

3) carpet 관련 for문

{ "id": dashboard.id,  "carpet": [
 	{
		"id": carpet.id,
		"color_id"  : carpet.carpet_type.color.id,
		"color_name": carpet.carpet_type.color.name,
		"thumbnail_url": carpet.carpet_type.thumbnail_url
     }for carpet in dashboard.carpet_set.select_related('carpet_type','carpet_type__color').filter(dashboard_id = dashboard.id)]}

carpet 관련 내용들을 미리 쿼리해두기 위해서 select_related를 이용했다.

filter를 이용하여 dashboard에 따른 carpet내용을 가지고 올 수 있게했다.


처음에는 위와 같이 딕셔너리 안의 딕셔너리 ... 형식으로 코드를 짰다.
위의 코드는 frontend가 데이터를 가지고오기 귀찮다는 단점이 있는데, 이 단점을 해결하기 위해서 하나의 딕셔너리에 모든 내용을 담는 방식으로 코드를 바꾸게 되었다.

  • 최종 코드
 class CarpetView(View):
     def get(self,request,mvl_id):

         carpet_list = [
             { "seat_id"           : carpet.dashboard.seat.id,
               "dashboard_id"      : carpet.dashboard.id,
               "carpet_id"         : carpet.id,
               "color_id"   	   : carpet.carpet_type.color.id,
               "carpet_color_name" : carpet.carpet_type.color.name,
               "carpet_thumbnail"  : carpet.carpet_type.thumbnail_url
              } for carpet in Carpet.objects.select_related('carpet_type','dashboard','carpet_type__color').filter(dashboard__seat__model_version_line_id=mvl_id)]

model_version_line이 seat에만 연결되어 있는 모델이기 때문에
처음에는 filter에서 model_version_line --> seat 를 가져오고 그 이후 seat --> dashboard --> carpet을 가져오는 형식으로 코드를 짰다.

최종 코드에서는 위의 방식을 이용하지 않고 dashboard --> seat --> model_version_line을 통하는 형식으로 코드를 만들었다.

filter(dashboard__seat__model_version_line_id=mvl_id)

위와 같이 __ 을 이용하여 연결된 table을 타고 타고 들어갈 수 있다.

select_related로 먼저 쿼리를 해두어서 중복 쿼리 발생을 줄였다.

2개의 댓글

comment-user-thumbnail
2020년 5월 5일

두콩쓰...

1개의 답글