Python postgreSQL sqlalchemy запрашивает столбец DATERANGE - PullRequest
0 голосов
/ 12 декабря 2018

У меня есть система бронирования, и я сохраняю забронированный диапазон дат в столбце DATERANGE:

booked_date = Column(DATERANGE(), nullable=False)

Я уже знаю, что могу получить доступ к фактическим датам с помощью booked_date.lower или booked_date.upper

Например, я делаю это здесь:

for bdate in room.RoomObject_addresses_UserBooksRoom: 
    unaviable_ranges['ranges'].append([str(bdate.booked_date.lower),\
    str(bdate.booked_date.upper)])

Теперь мне нужно отфильтровать мои заказы по заданному диапазону дат.Например, я хочу увидеть все заказы в период с 01.01.2018 по 10.01.2018.

Обычно это просто, потому что даты можно сравнить так: date <= other date

Но если я сделаю это сDATERANGE:

the_daterange_lower = datetime.strptime(the_daterange[0], '%d.%m.%Y')
the_daterange_upper = datetime.strptime(the_daterange[1], '%d.%m.%Y')

bookings = UserBooks.query.filter(UserBooks.booked_date.lower >= the_daterange_lower,\
UserBooks.booked_date.upper <= the_daterange_upper).all()

Я получаю ошибку:

AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with UserBooks.booked_date has an attribute 'lower'

EDIT

Я нашел лист сполезные операторы диапазона и похоже, что есть лучшие варианты сделать то, что я хочу сделать, но для этого мне нужно как-то создать range variable, но Python не может это сделать.Так что я все еще в замешательстве.

В моей базе данных мои записи в столбце с указанием даты выглядят так:

[2018-11-26,2018-11-28)

РЕДАКТИРОВАТЬ

Я пытаюсь использоватьродной SQL, а не sqlalchemy, но я не понимаю, как создать объект daterange.

bookings = db_session.execute('SELECT * FROM usersbookrooms WHERE booked_date && [' + str(the_daterange_lower) + ',' + str(the_daterange_upper) + ')')

1 Ответ

0 голосов
/ 12 декабря 2018

Запрос

the_daterange_lower = datetime.strptime(the_daterange[0], '%d.%m.%Y')
the_daterange_upper = datetime.strptime(the_daterange[1], '%d.%m.%Y')

bookings = UserBooks.query.\
    filter(UserBooks.booked_date.lower >= the_daterange_lower,
           UserBooks.booked_date.upper <= the_daterange_upper).\
    all()

может быть реализован с использованием оператора "range hasable" <@.Чтобы передать правильный операнд, вы должны создать экземпляр psycopg2.extras.DateRange, который представляет значение Postgresql daterange в Python:

the_daterange_lower = datetime.strptime(the_daterange[0], '%d.%m.%Y').date()
the_daterange_upper = datetime.strptime(the_daterange[1], '%d.%m.%Y').date()

the_daterange = DateRange(the_dateranger_lower, the_daterange_upper)

bookings = UserBooks.query.\
    filter(UserBooks.booked_date.contained_by(the_daterange)).\
    all()

Обратите внимание, что атрибуты lower и upper являются частью типов psycopg2.extras.Range.Типы столбцов диапазона SQLAlchemy не предоставляют такие, как ваши ошибки.


Если вы хотите использовать необработанный SQL и передавать диапазоны дат, вы можете использовать те же самые объекты DateRange для передачи значений, а также:

bookings = db_session.execute(
    'SELECT * FROM usersbookrooms WHERE booked_date && %s',
    (DateRange(the_daterange_lower, the_daterange_upper),))

Вы также можете строить литералы вручную , если хотите:

bookings = db_session.execute(
    'SELECT * FROM usersbookrooms WHERE booked_date && %s::daterange',
    (f'[{the_daterange_lower}, {the_daterange_upper})',))

Хитрость заключается в том, чтобы собрать литерал в Python и передать его какединственное значение - использование заполнителей, как всегда.Следует избегать любых возможностей внедрения SQL-кода;единственное, что может произойти, это то, что литерал имеет неверный синтаксис для daterange.В качестве альтернативы вы можете передать границы конструктору диапазона :

bookings = db_session.execute(
    'SELECT * FROM usersbookrooms WHERE booked_date && daterange(%s, %s)',
    (the_daterange_lower, the_daterange_upper))

В общем, проще использовать типы Psycopg2 Range и позволить им обрабатывать детали.

...