마이리얼트립 클론③API-Products

박민하·2022년 7월 18일
0

PROJECT

목록 보기
16/17
post-thumbnail

<Fake_trip>
국내 숙소 카테고리를 한정으로 검색, 조건별 필터링, 예약 기능 구현

✅ Model

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})'

✅ View

✔ import

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)
profile
backend developer 🐌

0개의 댓글