Вопрос или проблема
У меня есть следующий код:
overlapping: Sequence[Booking] = (
await session.exec(
select(Booking)
.join(Apartment)
.join(User)
.where(
Range(
lower=booking.end_date,
upper=booking.cleaning_deadline,
bounds="[]",
).overlaps(Range(Booking.end_date, Booking.cleaning_deadline))
)
)
).all()
Он выдает следующий вывод:
Traceback (most recent call last):
...
File "/home/jakov/Projects/intis/src/web/server.py", line 120, in import_calendar
).overlaps(Range(Booking.end_date, Booking.cleaning_deadline))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jakov/.cache/pypoetry/virtualenvs/intis-I4I4liA8-py3.12/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/ranges.py", line 381, in overlaps
self._compare_edges(slower, slower_b, olower, olower_b) >= 0
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jakov/.cache/pypoetry/virtualenvs/intis-I4I4liA8-py3.12/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/ranges.py", line 274, in _compare_edges
if value1 < value2: # type: ignore
^^^^^^^^^^^^^^^
File "/home/jakov/.cache/pypoetry/virtualenvs/intis-I4I4liA8-py3.12/lib/python3.12/site-packages/sqlalchemy/sql/elements.py", line 3938, in __bool__
raise TypeError("Boolean value of this clause is not defined")
TypeError: Boolean value of this clause is not defined
В общем, я хочу выполнить этот запрос через ORM:
select * from booking b where (b.end_date , b.cleaning_deadline) overlaps (?, ?);
Я протестировал это в базе данных, и это работает, но я не могу заставить SQLAlchemy сделать то, что я хочу.
Ответ или решение
Ваша проблема связана с тем, что вы пытаетесь использовать метод overlaps
из библиотеки SQLAlchemy для создания запроса, который проверяет, пересекаются ли два диапазона дат. Судя по вашему коду и стеку вызовов, возникает ошибка, связанная с тем, как вы определяете диапазоны в запросе.
Чтобы корректно использовать Range.overlaps
, вам нужно убедиться, что вы правильно задаете стек диапазонов для сравнения. Ваша цель состоит в том, чтобы проверить, пересекаются ли диапазоны дат, которые вы хотите получить.
Вот исправленный вариант вашего кода с пояснениями:
from sqlalchemy import select
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from sqlalchemy.dialects.postgresql import RANGE
from typing import Sequence
# Предполагая, что Booking, Apartment и User уже определены как модели SQLAlchemy
async def get_overlapping_bookings(session: AsyncSession, booking: Booking) -> Sequence[Booking]:
overlapping: Sequence[Booking] = (
await session.execute(
select(Booking)
.join(Apartment)
.join(User)
.where(
RANGE(
lower=booking.end_date,
upper=booking.cleaning_deadline,
bounds="[]"
).overlaps(RANGE(Booking.end_date, Booking.cleaning_deadline, bounds="[]"))
)
)
).scalars().all()
return overlapping
Объяснения:
-
Правильная структура запроса: Используйте метод
execute
для выполнения SQL-запроса вместоexec
. Также убедитесь, что используетеscalars()
для извлечения результатов из запроса. -
Параметры диапазона: Убедитесь, что вы задаете границы одинаково для обоих диапазонов. Вы используете
bounds="[]"
, что значит, что границы являются закрытыми (включают конечные значения). Если ваши данные могут включать границы (например, еслиend_date
одной брони совпадает сcleaning_deadline
другой), вам нужно учесть это. -
Асинхронная работа с сессией: Если вы используете
AsyncSession
, не забудьте правильно его настроить и закрыть. В данном примере предполагается, чтоsession
передается в функцию как асинхронная сессия. -
Ошибка, связанная с булевым значением: причиной ошибки может быть некорректное использование или сравнение объектов диапазонов. Убедитесь, что вы используете их правильно и всегда возвращаете корректные объекты.
Таким образом, исправив вышеописанные моменты, вы сможете успешно выполнять запрос для поиска пересекающихся резервирований.