2015-09-14 3 views
1

Я хотел бы отфильтровать аннотацию с помощью Django ORM. Многие из статей, которые я нашел здесь ТАК достаточно устарели, нацеливание Джанго обратно в 1,2 до 1,4 дней:Современные методы фильтрации аннотации Django?

  • Filtering only on Annotations in Django - этот вопрос с 2010 года предлагает использовать в extra положение, которое не рекомендованное официальные документы Джанго
  • Django annotation with nested filter - Подобные предложения предусмотрены в этом вопросе с 2011.

Django 1.8 добавляет conditional aggregation, что кажется, что я мог бы, но я не могу вполне понять синтаксис, который я В конце концов, мне нужно. Вот мои модели и сценарии я пытаюсь достичь (я упростил модели для краткости):

class Project(models.Model): 
    name = models.CharField() 
    ... snip ... 

class Milestone_meta(models.Model): 
    name = models.CharField() 
    is_cycle = models.BooleanField() 

class Milestone(models.Model): 
    project = models.ForeignKey('Project') 
    meta = models.ForeignKey('Milestone_meta') 
    entry_date = models.DateField() 

Я хочу, чтобы каждый Project (со всеми полями), наряду с Max(entry_date) и Min(entry_date) для каждого связанного Milestone, но только для тех Milestone записей, у которых Milestone_meta имеет флаг is_cycle, равный True. Другими словами:

  • Для каждой записи проекта дайте мне максимальную и минимальную дату входа в Milestone, но только если соответствующий флаг Milestone_meta имеет заданный флаг, равный True.

На данный момент я получаю список проектов, а затем получать Max и Min Вехи в цикле, в результате попаданий + 1 базы данных N (который становится медленным, как и следовало ожидать):

pqs = Projects.objects.all() 

for p in pqs: 
    (theMin, theMax) = getMilestoneBounds(p) 
    # Use values from p and theMin and theMax 

... 

def getMilestoneBounds(pid): 
    mqs = Milestone.objects.filter(meta__is_cycle=True) 
    theData = mqs.aggregate(min_entry=Min('entry_date'),max_entry=Max('entry_date')) 

    return (theData['min_entry'], theData['max_entry']) 

Как я могу уменьшить это до одного или двух запросов?

+0

Я бы сказал, что это определенно случай, когда нужно использовать дополнительный или даже необработанный sql. – e4c5

+0

Документы показывают, что 'extra' в конечном итоге будет устаревшим. В идеале я бы хотел в какой-то степени использовать что-то, что в будущем доказано. –

+0

ну, то используйте более мощные и даже лучше сырые sql – e4c5

ответ

0

Насколько я знаю, вы не можете получить все необходимое project объектов в одном запросе.

Однако, если вам не нужны объекты и может работать только с их идентификатором, один путь состоял бы быть-

Milestone.objects.filter(meta__is_cycle=True).values('project').annotate(min_entry=Min('entry_date')).annotate(max_entry=Max('entry_date')) 

Это даст список dicts, имеющих данные различных проектов, вы можете используйте их «id» для поиска объектов по мере необходимости.

Смежные вопросы