<Fake_trip>
국내 숙소 카테고리를 한정으로 검색, 조건별 필터링, 예약 기능 구현
from django.db import models
class Category(models.Model):
name = models.CharField(max_length = 50)
class Meta:
db_table = 'categories'
def __str__(self):
return f'{self.name} ({self.pk})'
class Product(models.Model):
name = models.CharField(max_length = 100)
grade = models.IntegerField(null = True)
check_in = models.CharField(max_length = 20)
check_out = models.CharField(max_length = 20)
address = models.CharField(max_length = 255, default = '')
latitude = models.DecimalField(max_digits = 13, decimal_places = 10)
longtitude = models.DecimalField(max_digits = 13, decimal_places = 10)
region = models.ForeignKey('Region', on_delete = models.SET_NULL, null = True)
amenity = models.ManyToManyField('Amenity', db_table = 'product_amenity')
category = models.ForeignKey('Category', on_delete = models.SET_NULL, null = True)
user = models.ManyToManyField(
'users.User',
through = 'users.Review',
through_fields = ('product', 'user')
)
class Meta():
db_table = 'products'
def __str__(self):
return f'{self.name} ({self.pk})'
class Room(models.Model):
name = models.CharField(max_length = 100)
product = models.ForeignKey('Product', on_delete = models.CASCADE)
price = models.DecimalField(max_digits = 10, decimal_places = 2)
quantity = models.IntegerField(default = 1)
size = models.IntegerField()
min_guest = models.IntegerField(default = 2)
max_guest = models.IntegerField(default = 2)
class Meta():
db_table = 'rooms'
class Region(models.Model):
name = models.CharField(max_length = 50)
class Meta():
db_table = 'regions'
def __str__(self):
return f'{self.name} ({self.pk})'
class ProductImage(models.Model):
url = models.CharField(max_length = 255)
product = models.ForeignKey('Product', on_delete = models.CASCADE)
is_main = models.BooleanField()
class Meta():
db_table = 'product_images'
class RoomImage(models.Model):
url = models.CharField(max_length = 255)
room = models.ForeignKey('Room', on_delete = models.CASCADE)
is_main = models.BooleanField()
class Meta():
db_table = 'room_images'
class Amenity(models.Model):
name = models.CharField(max_length = 30)
class Meta():
db_table = 'amenities'
def __str__(self):
return f'{self.name} ({self.pk})'
import json
from django.http import JsonResponse
from django.views import View
from django.db.models import Q, Min, Avg, Count, IntegerField, Max
from django.db.models.functions import Coalesce
from datetime import datetime, timedelta
from products.models import Product, Room, Amenity
from orders.models import Reservation
from users.models import Review
class ProductListView(View):
def get(self, request):
products = ['name', 'region', 'grade', 'rating', 'sort', 'search', 'guest', 'category']
for product in products:
globals()["{}".format(product)] = request.GET.get(product)
amenity = request.GET.getlist('amenity')
guest = request.GET.get('guest',0)
start_date = request.GET.get('start_date',0)
end_date = request.GET.get('end_date',1000000)
min_price = request.GET.get('min_price',0)
max_price = request.GET.get('max_price',1000000)
offset = int(request.GET.get('offset', 0))
limit = int(request.GET.get('limit', 10))
def rooms_full(product,start_date,end_date):
reservations = Reservation.objects.filter(room__product = product)
rooms = Room.objects.filter(product = product)
search_date = set(pandas.date_range(start_date,end_date)[:-1])
is_sold_out = []
for room in rooms:
for reservation in room.reservation_set.all().filter(room__price__range=[min_price,max_price]).filter(room__max_guest__gte=guest):
reservation_date = set(pandas.date_range(reservation.start_date,reservation.end_date)[:-1])
if search_date & reservation_date:
room.quantity -= 1
if bool(room.quantity) == False:
is_sold_out.append(reservation.room_id)
return is_sold_out
def room_min_price(product, min_price, max_price, guest, start_date, end_date):
min_price = product.room_set.filter(price__range=[min_price,max_price]).filter(max_guest__gte=guest)\
.exclude(id__in=rooms_full(product,start_date,end_date))\
.aggregate(min = Min('price',output_field=IntegerField()))['min']
return min_price
def product_amenity(product, amenity):
a=0
if amenity != []:
for j in amenity:
if j in [i.name for i in product.amenity.all()]:
a += 1
if a == len(amenity):
return [i.name for i in product.amenity.all()]
else:
return [amenity.name for amenity in product.amenity.all()]
q = Q()
if search:
q &= (Q(name__contains = search) | Q(region__name__contains = search))
FILTER_SET = {
'region' : 'region__name',
'amenity' : 'amenity__name',
'grade' : 'grade__gte',
'guest' : 'room__max_guest__gte',
'[min_price,max_price]' : 'room__price__range',
'category' : 'category__name'
}
SORT_SET = {
'random' : '?',
'check_in-ascending' : 'check_in'
}
filter = { FILTER_SET.get(key) : value for key, value in request.GET.items() if FILTER_SET.get(key) }
order_key = SORT_SET.get(sort, 'id')
products = Product.objects.filter(**filter).filter(q).order_by(order_key).distinct()
results = [
{
'id' : product.id,
'name' : product.name,
'grade' : product.grade,
'address' : product.address,
'region' : product.region.name,
'check_in' : product.check_in,
'check_out' : product.check_out,
'latitude' : product.latitude,
'longtitude' : product.longtitude,
'category' : product.category.name,
'main_image': product.productimage_set.get(is_main=1).url,
'amenity' : [amenity.name for amenity in product.amenity.all()],
'avg_rate' : product.review_set.aggregate(avg = Avg('rating'))['avg'],
'price' :
{'default' : product.room_set.aggregate(min = Min('price',output_field=IntegerField()))['min'],
'min_price' : room_min_price(product, min_price, max_price, guest, start_date, end_date)
}
} for product in products if room_min_price(product, min_price, max_price, guest, start_date, end_date) != None \
and product_amenity(product, amenity) != None
][offset:offset+limit]
return JsonResponse({'results' : results}, status = 200)