장고 - 체크인/체크아웃에 예약가능한 숙소 정보 가져오기
- 이번 포스트에서는 필터 기능을 사용하여 유저가 선택한 체크인, 체크아웃 날짜에 예약 가능한 숙소를 검색할 수 있는 방법에 대해 알아볼 것이다.
ex) yanoljamvp_project
1. model 구현
- 경로 : stay(앱) > models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163# 숙소 정보 입력할 모델
class Stay(models.Model):
# 모텔, 호텔,리조트, 펜션/풀빌라, 게스트하우스 선택
category = models.ForeignKey(Category, on_delete=models.SET, null=True, blank=True, related_name="stays")
# 전경 사진(대표 사진) - 이미지 1개
mainImage = models.CharField(max_length=200, blank=True, null=True)
# 방 모든 사진 - 이미지 여러개
urlImage = models.TextField(blank=True, null=True)
# 숙소 이름(ex. 역삼 바레)
name = models.CharField(max_length=50)
# 유저 아이디(ex. positipman)
username = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name="stays")
# 숙소 위치(ex. 서울특별시 강남구 봉은사로 428)
location = models.CharField(max_length=100)
# 숙소 소개
introduce = models.TextField(blank=True)
# 초특가호텔 --> 초특가할인 변경 (사장이 당일특가로 가격 40% 이상 할인 시, 초특가할인 true로 설정)
# ForeignKey로 연결되어 있는 아래의 Room 모델에서 초특가할인 여부 확인
# 편의시설 및 서비스 항목 (상기 SERVICE_CHOICES 참고)
serviceKinds = MultiSelectField(choices=SERVICE_CHOICES, null=True, blank=True)
# 편의시설 및 서비스 설명
serviceIntroduce = models.TextField(blank=True)
# 이용안내
serviceNotice = models.TextField(blank=True)
# 픽업안내
pickupNotice = models.TextField(blank=True)
# 숙소 리스트에 보여질 위치
directions = models.TextField(blank=True)
# 찾아오시는 길
route = models.TextField(blank=True, null=True)
# 찜하기
like = models.ManyToManyField(User, blank=True, related_name="like_stay")
# 검색 관련 키워드
keywords = TaggableManager()
# Stay 객체 생성일 자동 저장
created = models.DateTimeField(auto_now_add=True)
# Stay 객체 수정일 자동 저장
updated = models.DateTimeField(auto_now=True)
# 관리자페이지에서 저장될 객체의 순서 기준 설정
class Meta:
ordering = ['category']
# 관리자페이지에서 보여지는 객체 이름 설정
def __str__(self):
return f"{self.category} - {self.name}"
# room --> 멀티 이미지 구현 필요
class Room(models.Model):
# 숙소 선택(호텔, 모텔, 펜션 외)
stay = models.ForeignKey(Stay, on_delete=models.CASCADE, related_name="rooms")
# 룸 이름
name = models.CharField(max_length=50)
urlImage = models.TextField(blank=True, null=True)
# 누가 어느 방을 예약했는지 확인
reserved = models.ManyToManyField(User, blank=True, related_name="reserved")
booker_set = models.ManyToManyField(User, through='Reservation')
# 대실 이용시간(ex. 3) --> 0이면 숙박만 가능
hoursAvailable = models.IntegerField(default=0, blank=True, null=True)
# 대실 운영시간(ex. 23) --> ~23:00
hoursUntil = models.IntegerField(default=0, blank=True, null=True)
# 숙박 체크인 가능 시간(ex. 22(오후 10시))
daysCheckIn = models.IntegerField(default=0)
# 숙박 체크아웃 마감시간(ex. 11(오전 11시))
daysCheckOut = models.IntegerField(default=0)
# 기준 인원
standardPersonnel = models.IntegerField()
# 최대 인원
maximumPersonnel = models.IntegerField()
# 대실 예약가
hoursPrice = models.CharField(max_length=50, blank=True)
# 숙박 예약가
daysPrice = models.CharField(max_length=50)
# 데이터 있으면, 해당 할인가로 표시
# views.py에서 할인률 40% 이상이면, 초특가할인으로 지정하도록 구현할 것
# 대실 예약가 할인
saleHoursPrice = models.CharField(max_length=50, blank=True)
# 숙박 예약가 할인
saleDaysPrice = models.CharField(max_length=50, blank=True)
# 기본정보
basicInfo = models.TextField(blank=True)
# 예약공지
reservationNotice = models.TextField(blank=True)
# 취소규정
cancelRegulation = models.TextField(null=True)
def __str__(self):
return f"{self.stay} - {self.name}"
# 유저가 예약할 때 필요한 정보 저장
class Reservation(models.Model):
# 예약할 룸을 가진 숙소
stay = models.ForeignKey(Stay, on_delete=models.SET_NULL, null=True, blank=True, related_name="reservations")
# 예약할 룸
room = models.ForeignKey(Room, on_delete=models.SET_NULL, null=True, blank=True, related_name="reservations")
# 최종 결제금액
finalPrice = models.CharField(max_length=50, default="")
# 대실일 경우, views.py에서 현재 시간이 만약 14시 30분이라면 15시부터 선택가능하도록
checkIn = models.DateTimeField(blank=True, null=True)
# 대실일 경우, views.py에서 해당 룸의 대실시간 고려하여 checkOut 시간 자동 저장
checkOut = models.DateTimeField(blank=True, null=True)
# 로그인한 유저아이디
username = models.ForeignKey(User, on_delete=models.CASCADE, related_name="reservations")
# 예약자 이름(views.py에서 default로 유저 이름 자동 설정) --> 변경 가능
booker = models.CharField(max_length=20)
# 예약자 폰 번호(views.py에서 default로 유저 폰번호 자동 설정) --> 변경 가능
phoneNumber = models.CharField(max_length=30)
wayToGo = models.CharField(max_length=10, blank=True, null=True)
# 대실, 숙박 선택(대실 혹은 숙박 예약하기 클릭 시, 해당 항목 True로 자동 변경)
checkHours = models.BooleanField(default=False)
checkDays = models.BooleanField(default=False)
# 예약한 날짜 자동 저장
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.username.username} has reserved the {self.room} in {self.stay}"
2. apis.py 작성
- 경로 : stay > apis.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61class StayListApi(generics.ListAPIView):
serializer_class = StaySerializer
permission_classes = [AllowAny,]
def get_queryset(self):
stays = Stay.objects.all()
...
# GET 요청으로 requestCheckIn(체크인날짜, string), requestCheckOut(체크아웃날짜, string)
# ex) 2019-07-23+15:00:00
if self.request.query_params.get('requestCheckIn', None) and self.request.query_params.get('requestCheckOut', None):
# ---------메인페이지 검색페이지에서 사용자가 체크인/체크아웃 설정한 경우 해당 숙소 필터링하는 코드---------
# default값으로 체크인 날짜는 현재일로 하여 1박2일 설정 필수 (프론트단에서 설정)
# 프론트단으로부터 사용자의 체크인/체크아웃 데이터를 string 형태로 받는다.
# str -> datetime 타입 변환 필요(ex. str = '2019-07-01') ex) 2019-07-01 11:00:00
requestCheckIn = self.request.query_params.get('requestCheckIn')
requestCheckOut = self.request.query_params.get('requestCheckOut')
# '+'를 빼고 나머지 문자열 저장(ex. 2019-07-01+22:00:00 --> 2019-07-01 22:00:00)
plus_sign = re.compile('[+]')
requestCheckIn = plus_sign.sub(' ', requestCheckIn)
requestCheckOut = plus_sign.sub(' ', requestCheckOut)
# string -> datetime 타입 변환
requestCheckIn = datetime.strptime(requestCheckIn, '%Y-%m-%d %H:%M:%S')
requestCheckOut = datetime.strptime(requestCheckOut, '%Y-%m-%d %H:%M:%S')
# 사용자가 요청한 체크아웃 시간이 체크인 시간보다 앞서 있을 때,
# searchResult를 False 값으로 설정하여 전송
if requestCheckOut < requestCheckIn:
return None
# 사용자가 요청한 체크인/체크아웃 시간에 예약 가능한 숙소 객체 선별
finalStays = []
for stay in stays:
rooms = stay.rooms.all()
for room in rooms:
roomReservation = room.reservations.all()
# 사용자가 요청한 체크인아웃 시간에 예약가능한 룸 --> 룸의 전체 checkInOut 객체수 == 사용자가 요청한 체크인/체크아웃시간과 겹치지 않는 룸의 checkInOut 객체 수
if roomReservation.count() == roomReservation.filter \
(Q(checkIn__gte=requestCheckOut) \
| Q(checkOut__lte=requestCheckIn)).count():
# 예약가능한 룸의 숙소 객체를 stay 변수에 저장
stay = room.stay
# finalObjects에 해당 숙소 객체 없다면 추가(숙소 객체 중복 방지)
if stay not in finalStays:
finalStays.append(stay)
# list 를 queryset 형태로 변경
stays = Stay.objects.filter(id__in=[object.id for object in finalStays])
# queryset 존재하지 않는다면 에러 발생
if not stays.exists():
return None
# requestCheckIn 또는 requestCheckOut 데이터가 전달되지 않은 경우 queryset으로 None 반환
if self.request.query_params.get('requestCheckIn', None) is None or self.request.query_params.get('requestCheckOut') is None:
return None
queryset = stays
return queryset
3. serializers.py 작성
- 경로 : stay > serializers.py
1
2
3
4class StaySerializer(serializers.ModelSerializer):
class Meta:
model = Stay
fields = '__all__'
4. urls.py 작성
- 경로 : stay > urls.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16from django.urls import path, include
from .views import *
from .apis import *
app_name = "stay"
urlpatterns_apis = [
...
path('stay/', StayListApi.as_view()),
...
]
urlpatterns = [
...
path('api/', include(urlpatterns_apis)),
]
Posted