2016-11-09 3 views
0

Я пытаюсь построить запрос, который фильтрует список отелей. Я только хочу показать бронирование отелей с сегодняшнего дня и в будущем. Запрос, который я построил, находится ниже, но не фильтрует результаты. Что я делаю не так?Sqlalchemy фильтр по дате

hotels = db.session.query(Hotel).\ 
    join(Location).\ 
    join(Rate).\ 
    filter(Location.city == city).\ 
    filter(Rate.arrive > datetime.utcnow()) 

Для фона, мои модели выглядеть следующим образом:

class Location(Base): 
    __tablename__ = 'locations' 

    id = Column(Integer, primary_key=True) 
    city = Column(String(50), nullable=False, unique=True) 

    hotels = relationship('Hotel', back_populates='location') 


class Hotel(Base): 
    __tablename__ = 'hotels' 

    id = Column(Integer, primary_key=True) 
    name = Column(String(100), nullable=False, unique=True) 
    phone_number = Column(String(20)) 
    parking_fee = Column(String(10)) 
    location_id = Column(Integer, ForeignKey('locations.id'), nullable=False) 

    location = relationship('Location', back_populates='hotels') 
    rates = relationship('Rate', back_populates='hotel', order_by='Rate.arrive') 


class Rate(Base): 
    __tablename__ = 'rates' 

    id = Column(Integer, primary_key=True) 
    price = Column(Numeric(6, 2)) 
    arrive = Column(Date, nullable=False) 
    link = Column(String(500), nullable=False) 
    updated = Column(DateTime, default=datetime.datetime.utcnow, nullable=False) 
    hotel_id = Column(Integer, ForeignKey('hotels.id'), nullable=False) 

    hotel = relationship('Hotel', back_populates='rates') 

Edit: Вот некоторые примерные данные:

Date: Friday, Sep 9 

Rate: 299.25 

Date: Sunday, Sep 11 

Rate: 261.75 

Date: Monday, Sep 12 

Rate: 261.75 

Date: Tuesday, Sep 13 

Rate: 261.75 

Date: Sunday, Sep 18 

Удаление фильтра (Rate.arrive> datetime.utcnow ()) не изменяет данные. Он выводится одинаково каждый раз, когда я запускаю запрос.

+0

Какие результаты вы получаете, когда вы выполняете запрос? Точно так же, когда вы удаляете 'filter (Rate.arrive> datetime.utcnow()'? Или результат пуст? * BTW, примеры данных и ожидаемые результаты запроса будут полезны. * – van

+0

Я добавил некоторые примеры данных. из результатов отображаются, когда фильтр установлен на месте, а также когда он удален. – Casey

+0

Ваш запрос возвращает экземпляр 'Hotel', а логика вашего запроса: * возвращение отелей в интересующем нас городе, где ** есть хотя бы one ** Rate после некоторой даты *. Поэтому, если после 'datetime.datetime.utcnow()' есть * хотя бы одна * 'Rate', отель будет возвращен. Это не то, что вы хотите? – van

ответ

1

Опция zero - это применить фильтр ставок после загрузки отелей, но это вызовет дополнительные запросы и не будет желательным.

Определить фильтры, которые используются в дальнейшем:

city = 'mumbai' 
arrive = datetime.date.today() 

Вариант-1: Нагрузка Rate интерес в первоначальном запросе

query = (
    session.query(Hotel, Rate) # this query will return pairs (Hotel, Rate) 
    .join(Location) 
    .join(Rate) 
    .filter(Location.city == city) 
    .filter(Rate.arrive > arrive) 
) 

# one could use the results directly as (Hotel, Rate) pairs 
# but we can also convert to the format: {hotel: rates} 
from collections import defaultdict 
hotels_list = defaultdict(list) 
for h, r in hotels: 
    hotels_list[h].append(r) 

# and print: 
for hotel, rates in hotels_list.items(): 
    print('', hotel) 
    for rate in rates: 
     print(' ', rate) 

Вариант-2: Кошелек на родственных связей Hotel.rates

Здесь мы используем contains_eager

hotels = (
    session.query(Hotel) 
    .join(Location) 
    .join(Rate) 
    .options(contains_eager(Hotel.rates)) # this is the key 
    .filter(Location.city == city) 
    .filter(Rate.arrive > arrive) 
) 


for hotel in hotels: 
    print('', hotel) 
    for rate in hotel.rates: # this now contains only sub-list, so be careful 
     print(' ', rate) 
+0

Аллилуйя спасибо! Я использовал метод contains_eager, и он отлично работал. Теперь мне просто нужно прочитать документы больше, чтобы я мог полностью понять, что происходит. – Casey

+0

Используя 'contains_eager' вы в основном * трюк *' sqlalchemy', чтобы думать, что он загрузил * all * отношения. Поэтому вы должны быть осторожны с его использованием. Но использование довольно элегантно, и я делаю это время от времени. – van