Я работаю над клонированием системы регистрации комнат airbnb в Django. У меня есть представление на основе классов (метод HTTP get), которое фильтрует комнаты, хранящиеся в базе данных, в соответствии с различными параметрами значения ключа строки запроса и возвращает эти комнаты. Параметры фильтра, предоставляемые через строку запроса:
location = request.GET.get('location')
adults = int(request.GET.get('adults', 0))
children = int(request.GET.get('children', 0))
infants = request.GET.get('infants', 0)
min_cost = float(request.GET.get('min_cost', 0))
max_cost = float(request.GET.get('max_cost', sys.maxsize))
property_type = request.GET.get('property_type', None)
place_type = request.GET.get('place_type', None)
check_in = request.GET.get('checkin', None)
check_in_date = datetime.datetime.strptime(check_in, '%Y-%m-%d') if check_in else None
check_out = request.GET.get('checkout', None)
check_out_date = datetime.datetime.strptime(check_out, '%Y-%m-%d') if check_out else None
min_beds = request.GET.get('min_beds', None)
min_bedrooms = request.GET.get('min_bedrooms', None)
min_baths = request.GET.get('min_baths', None)
amenities = request.GET.getlist('amenities', None)
languages = request.GET.getlist('languages', None)
Я решил сохранить все выражения фильтра как объекты Q (), используя операцию & =. Комнаты с уже забронированными датами и выбранными хозяином недоступными датами («заблокированная дата»), которые противоречат предоставленным check_in_date и check_out_date, будут отфильтрованы. После сохранения всех выражений Q () в переменной под названием «запросы» я передал «запросы» в качестве аргумента функции Room.objects.filter (). Параметры min_beds, min_bedrooms и min_baths были оценены после начальной фильтрации, чтобы я мог выполнить функцию annotate () для отфильтрованного набора запросов.
Следующий код работает, но мне интересно, есть ли более сжатый и эффективный способ фильтрации с точки зрения db-вызовов и временной сложности. Возможно, используя prefetch_related ()? На данный момент кажется, что существует слишком много повторяющихся операторов if, но я не мог придумать лучшего способа оценки случаев None для параметров строки запроса.
queries = (
Q(address__icontains = location) &
Q(max_capacity__gte = adults + children) &
Q(price__range = (min_cost, max_cost))
)
if check_in_date and check_out_date:
queries &= (
~Q(blockeddate__start_date__range = (check_in_date, check_out_date)) &
~Q(blockeddate__end_date__range = (check_in_date, check_out_date)) &
~Q(booking__start_date__range = (check_in_date, check_out_date)) &
~Q(booking__end_date__range = (check_in_date, check_out_date))
)
if property_type:
queries &= Q(property_type__name = property_type)
if place_type:
queries &= Q(place_type__name = place_type)
if amenities:
q_expressions = [Q(amenities__name = amenity) for amenity in amenities]
for expression in q_expressions:
queries &= expression
if languages:
q_expressions = [Q(host__userlanguage__language__name = language) for language in languages]
for expression in q_expressions:
queries &= expression
room_qs = Room.objects.filter(queries)
if min_beds:
room_qs = room_qs.annotate(num_beds=Sum('bedroom__bed__quantity')).filter(num_beds__gte = min_beds)
if min_bedrooms:
room_qs = room_qs.annotate(num_bedrooms=Count('bedroom')).filter(num_bedrooms__gte = min_bedrooms)
if min_baths:
room_qs = room_qs.annotate(num_baths=Count('bath')).filter(num_baths__gte = min_baths)