마이리얼트립의 내 여행 페이지를 보면 다음과 같이 예약 목록이 나온다.
왕복여행을 예약했으면 같은 예약번호로 가는편 오는편 일정이 편도처럼 따로 뜨고
각각 날짜에 따라서 정렬돼서 뜬다.
필요한건 비행편수 하나당 예약번호, 예약상태, 출발날짜, 출발지, 도착지, 항공사이름, 항공사로고이미지인데
모델링이 이렇게 생겼다.
비행기가 왕복이면 가는편 오는편 둘다 각각 가져와야되고 편도면 하나만 가져와야하는데
티켓에는 인원수 * (가는편+오는편)이 다 있고 가는편 오는편을 따로 보려면
부킹 전체 목록을 가지고 하나씩 확인하면서 승객 테이블에 접근해서 해당 예약 승객 아무나 한명이 가지고 있는 티켓을 확인해서 그 티켓(들)을 이용해서 날짜, 장소, 항공사정보 등을 뽑았어야 했다.
그래서 이걸 각 부킹의 무조건 첫번째 승객에서 뽑아낸 티켓을 가지고 모든 예약 목록의 데이터를 뽑아내는것까지는 했는데
이걸 날짜순으로 정렬해서 보여줘야하는데
부킹에서 시작을 해서 그 안에 있는 티켓들의 정보를 이중포문으로 뽑아낸 거라서
구조상 티켓의 날짜를 기준으로 정렬을 할 수가 없었다.
for booking in bookings:
for ticket in booking.passenger_set[0].ticket_set.all():
...
이런느낌
정렬을 해야되니까 bookings를 돌면서 그 안의 티켓의 날짜를 가져오는 방법을 사용하지 않고 booking 자체에 날짜정보가 있어야 하는데
그래서 모델링을 수정해서 검색할때 넣어야하는 정보(출발지 도착지 출발날짜 도착날짜)를 모두 bookings테이블에 넣고 편도일 경우는 도착날짜가 없으니까 도착날짜를 null=True로 지정하는 방식으로 변경하는 쪽도 생각을 해봤는데 프론트쪽에서도 예약시 백엔드에 주는 데이터를 변경해야 해서 고민하다가 결국 모델을 변경하지 않고 같은 방식으로 동작할 수 있도록 진행하기로 했다.
일단
1. booking정보에 날짜정보까지 있어야 정렬이 가능하고
2. 왕복예약을 올때 갈때 각각 분리해야 예약번호에 상관없이 섞어놓고 정렬이 가능하다
그래서
1. annotate를 사용해서 해당 booking이 갖고있는 ticket의 출발날짜를 min_departure_time, max_departure_time으로 붙여줬다.
from django.db.models import Min, Max
...
bookings = Booking.objects.select_related('booking_status')\
.annotate(min_departure_time=Min('ticket__flight_detail__departure_time'), max_departure_time=Max('ticket__flight_detail__departure_time'))\
.filter(user = user, booking_status_id = status_set.get(status_id))
annotate는 가상의 컬럼을 만들어주는거랑 비슷하다. 해당 booking이 가지고 있는 티켓의 출발시간중 가장 작은값과 큰값을 각각 넣었는데
이렇게 하면 편도인 예약은 min_departure_time, max_departure_time의 값이 같을거고 왕복이면 각각 다른 값을 갖게 된다.
2. 왕복이면 해당 booking을 복제해서 booking자체를 두개를 만들어버렸다.
booking_list = []
for booking in bookings:
booking_list.append(booking)
if booking.min_departure_time != booking.max_departure_time:
booking_return = bookings.annotate(min_departure_time=Min('ticket__flight_detail__departure_time'), max_departure_time=Max('ticket__flight_detail__departure_time')).get(id = booking.id)
booking_return.min_departure_time = booking_return.max_departure_time
booking_list.append(booking_return)
부킹을 하나씩 booking_list에 담으면서 왕복인지 확인을 하고 왕복이면 같은 booking을 한번더 리스트에 담으면서 min_departure_time에 max_departure_time의 값을 넣어준다.
그러면 min_departure_time으로 정렬을 하면 모든 여정들을 전부 편도 기준으로 날짜순으로 정렬을 할 수 있게 된다.
3. 정렬
from operator import attrgetter
booking_list.sort(key = attrgetter('min_departure_time'))
sort의 key 속성을 이용해서 booking_list를 정렬했다.
이러면 이제 booking_list에 있는 booking을 하나씩 꺼내면서 booking에 있는 정보만 뽑아서 전달하면 마이리얼트립과 같은 형태의 내 예약 페이지 리스트를 만들 수 있다.
flight_detail = FlightDetail.objects.all().select_related('flight_route__airplane__airline', 'flight_route__departure', 'flight_route__destination')
result = [{
'booking_id' : booking.id,
'booking_number' : booking.booking_number,
'booking_status' : booking.booking_status.name,
'departure_name' : flight_detail.filter(ticket__booking__id=booking.id, departure_time = booking.min_departure_time).first().flight_route.departure.korean_name,
'departure_date' : booking.min_departure_time,
'arrival_name' : flight_detail.filter(ticket__booking__id=booking.id, departure_time = booking.min_departure_time).first().flight_route.destination.korean_name,
'arrival_date' : flight_detail.filter(ticket__booking__id=booking.id, departure_time = booking.min_departure_time).first().arrival_time,
'airline' : {
'id' : flight_detail.filter(ticket__booking__id=booking.id).first().flight_route.airplane.airline.id,
'name' : flight_detail.filter(ticket__booking__id=booking.id).first().flight_route.airplane.airline.name,
'logo' : flight_detail.filter(ticket__booking__id=booking.id).first().flight_route.airplane.airline.logo_url,
}
}for booking in booking_list]
'wecode' 카테고리의 다른 글
Code Kata | Week3 - Day2 (0) | 2022.09.14 |
---|---|
마이허니트립 | 프로젝트 회고 (0) | 2022.08.29 |
마이허니트립 | 예약 api transaction.atomic() 적용 (0) | 2022.08.17 |
마이허니트립 | 예약페이지 승객정보 bulk_create (0) | 2022.08.14 |
마이허니트립 | 예약상태 지정에 Enum사용하기 (0) | 2022.08.07 |