Проблема при написании запроса к базе данных - PullRequest
2 голосов
/ 04 февраля 2010

У меня есть две модели, Location и Event, которые связаны с ForeignKey на модели Event. Модели разбиваются следующим образом:

class Location(models.Model):
    city = models.CharField('city', max_length=25)
    slug = models.SlugField('slug')

class Event(models.Model):
    location = models.ForeignKey(Location)
    title = models.CharField('title', max_length=75)
    start_date = models.DateTimeField('start_date')
    end_date = models.DateTimeField('end_date')

В каждой локации есть несколько событий, упорядоченных по убыванию start_date. Запрос, который я пытаюсь сделать, возвращает следующее предстоящее событие для каждого из местоположений.

В идеале я хотел бы сделать это в одном запросе (я не хочу запускать запрос для каждого местоположения, так как это приведет к большому количеству ненужных обращений к базе данных). Я пытался использовать ORM в Django, и я также пытался использовать сырой SQL, но я столкнулся с некоторым препятствием.

Любая помощь будет принята с благодарностью.

Обновление

Я нашел потенциальное решение, хотя я не уверен, что это лучший метод. Это работает, чего должно быть достаточно, но мне любопытно посмотреть, каким будет лучший способ сделать это.

Во всяком случае, код, который я написал, выглядит так:

l = Location.objects.select_related()
qs = None

# Concatenate the related event querysets into a new queryset
for e in l:
    if qs is None:
        qs = e.event_set.all()
    else:
        qs = qs | e.event_set.all()

# Order a slice of the queryset by start_date ascending
qs = sorted(qs[:l.count()], key=lambda s: s.start_date)

Ответы [ 4 ]

1 голос
/ 04 февраля 2010
select id, (
    select * from event 
    where location=location.id 
    and start_date>NOW() 
    order by start_date asc 
    limit 1
    )
 from location
1 голос
/ 04 февраля 2010

"В идеале я хотел бы сделать это в одном запросе (я не хочу выполнять запрос для каждого местоположения, так как это вызовет много ненужных обращений к базе данных)."

Это неверное предположение.

1) ORM Джанго использует кеш.Он может не запрашивать базу данных так часто, как вы думаете.Базы данных имеют кеш.Стоимость запроса также может быть не такой, как вы думаете.

2) У вас есть select_related.ORM может сделать объединение для вас.http://docs.djangoproject.com/en/dev/ref/models/querysets/#id4

Просто напишите самый простой из возможных циклов для извлечения Locations и Events.В очень маловероятном случае, если это самая медленная часть вашего приложения (и вы можете доказать , что она самая медленная), затем добавьте select_related и посмотрите, насколько это улучшит ситуацию.

Пока вы не докажете, что этот конкретный запрос убивает ваше приложение, продолжайте и не беспокойтесь о "попаданиях в базу данных".

Следующее событие в каждом месте?

[ l.event_set.order_by( start_date ).all()[0] for l in Location.objects.select_related().all() ]

Или, возможно,

events = []
for l in Location.objects.select_related().all():
    events.append( l.event_set.order_by( start_date ).all()[0] )

И верните это в шаблон для визуализации.

Не отклоняйте это, пока вы не сравните его и не докажете, что это узкое местов вашем приложении.

0 голосов
/ 04 февраля 2010

Может пригодиться что-то вроде следующего:

SELECT * FROM EVENTS V
  WHERE (V.LOCATION, V.START_DATE) IN
    (SELECT E.LOCATION, MIN(E.START_DATE)
       FROM EVENTS E
       WHERE E.START_DATE >= NOW
       GROUP BY E.LOCATION)

Делись и наслаждайся.

0 голосов
/ 04 февраля 2010

Я думаю, вы должны посмотреть на агрегацию django текст ссылки , поэтому ваш результат будет увеличен по местоположению с условием фильтрации будущих / просроченных событий, а min (start_time) возвращает время следующего события

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...