2015-06-25 1 views
0

оригинальной проблема вызвано довольно неудобные моделями велосипедных ссылка:Wrong GROUP BY полей в Django аннотировать запрос

# A -> B -> A 

class A: 
    b = models.ForeignKey('B', null=True, blank=True) 

class B: 
    a = models.ForeignKey('A') 

Теперь, когда я пытаюсь аннотировать запрос, он всегда использует GROUP BY в идентификационном от LEFT OUTER JOIN (T3.id в примере ниже) вместо a.id.

Пример:

A.objects.select_related('b', 'b__a').annotate(reviews=Count('reviews')) 

Сгенерированный SQL:

SELECT 
    `a`.`id`, 
    `b`.`id`, 
    T3.`id`, 
FROM 
    `a` 
     LEFT OUTER JOIN 
    `b` ON (`a`.`b_id` = `b`.`id`) 
     LEFT OUTER JOIN 
    `a` T3 ON (`b`.`a_id` = T3.`id`) 
WHERE 
    `a`.`id` IN (1, 2, 3, 4, 5) 
GROUP BY T3.`id` 
ORDER BY NULL; 

Я знаю, что я могу сделать следующие вещи:

  1. Изменить модель не делать ссылки на велосипеде (к сожалению, не может сделать что прямо сейчас)
  2. Может использовать .extra() вместо аннотаций (Я бы попытаться избежать его)
  3. Удалить .select_related вызова() (не могу сделать из-за проблемы с производительностью)

UPD: Использование GROUP BY T3.id исключат результаты, где абы = = None

Лучшим решением для меня было бы просто указать правильное поле в предложении GROUP BY, но я не знаю, как это сделать. Является ли это возможным? Есть ли другой способ решить проблему? Благодарю.

+0

Не 'T3 == a', от' А, как T3'? Не уверен, чего вы пытаетесь достичь здесь. – mccc

+0

Использование GROUP BY T3.id исключает результаты, где a.b == None, пока этого не ожидалось. – ZAN

+0

Что касается того, чего я пытался достичь - модель может иметь родительский объект через B. Я знаю, что это не лучший подход, но это была своего рода эволюция модели. – ZAN

ответ

0

Открыт Джанго компилятор:

def collapse_group_by(self, expressions, having): 
    # If the DB can group by primary key, then group by the primary key of 
    # query's main model. Note that for PostgreSQL the GROUP BY clause must 
    # include the primary key of every table, but for MySQL it is enough to 
    # have the main table's primary key. Currently only the MySQL form is 
    # implemented. 
    # MySQLism: however, columns in HAVING clause must be added to the 
    # GROUP BY. 
    if self.connection.features.allows_group_by_pk: 
     # The logic here is: if the main model's primary key is in the 
     # query, then set new_expressions to that field. If that happens, 
     # then also add having expressions to group by. 
     pk = None 
     for expr in expressions: 
      if (expr.output_field.primary_key and 
        getattr(expr.output_field, 'model') == self.query.model): 
       pk = expr 
       # HERE BREAKPOINT REQUIRED 
     if pk: 
      expressions = [pk] + [expr for expr in expressions if expr in having] 
    return expressions 

Таким образом, функция collapse_group_by не останавливается ищет рк даже нашла уже, поэтому группировка по делается T3.id вместо A.id (и, таким образом, я отсутствуют результаты). Чтобы устранить проблему, точка останова требуется внутри цикла (помечена в комментариях).

UPD: проблема уже исправлена ​​в Django 1.8.2 версии https://code.djangoproject.com/ticket/24748

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