Django 1.0/1.1 переписывает самосоединение

Есть ли способ переписать этот запрос с помощью объекта Django QuerySet:

SELECT b.created_on, SUM(a.vote)
FROM votes a JOIN votes b ON a.created_on <= b.created_on
WHERE a.object_id = 1
GROUP BY 1

Где voices — это таблица, object_id — это int, который встречается несколько раз (внешний ключ — хотя здесь это не имеет значения), а created_on — это дата и время.

FWIW, этот запрос позволяет получить оценку в любое время в прошлом, суммируя все предыдущие голоса по этому object_id.


person Adam Nelson    schedule 04.03.2009    source источник


Ответы (3)


Я почти уверен, что запрос не может быть создан с помощью Django ORM. Новый код агрегации Django довольно гибкий, но я не думаю, что он может делать именно то, что вам нужно.

Вы уверены, что запрос работает? Кажется, вам не хватает проверки, что b.object_id равен 1.

Этот код должен работать, но он состоит из более чем одной строки и не так эффективен.

from django.db.models import Sum

v_list = votes.objects.filter(object__id=1)

for v in v_list:
    v.previous_score = votes.objects.filter(object__id=1, created_on__lte=v.created_on).aggregate(Sum('vote'))["vote__sum"]

Агрегация доступна только в транке, поэтому вам может потребоваться обновить установку django, прежде чем вы сможете это сделать.

person Andrew Wilkinson    schedule 05.03.2009
comment
Ваш, вероятно, самый близкий вариант, но, как вы говорите, неэффективный. Я решил просто выполнить sql напрямую, используя .extra(). - person Adam Nelson; 06.03.2009

Агрегация не является проблемой; проблема здесь в том, что ORM Django просто не выполняет соединения с чем-либо, кроме ForeignKey, AFAIK.

person Carl Meyer    schedule 05.03.2009

Это то, что я использую сейчас. По иронии судьбы, sql не работает, но суть его в следующем:

    def get_score_over_time(self, obj):
    """
    Get a dictionary containing the score and number of votes 
    at all times historically
    """
    import pdb; pdb.set_trace();
    ctype = ContentType.objects.get_for_model(obj)
    try:
        query = """SELECT b.created_on, SUM(a.vote)
                        FROM %s a JOIN %s b 
                        ON a.created_on <= b.created_on
                        WHERE a.object_id = %s
                        AND a.content_type_id = %s
                        GROUP BY 1""" % (
            connection.ops.quote_name(self.model._meta.db_table),
            connection.ops.quote_name(self.model._meta.db_table),
            1,
            ctype.id,
            )
        cursor = connection.cursor()
        cursor.execute(query)
        result_list = []
        for row in cursor.fetchall():
            result_list.append(row)
    except models.ObjectDoesNotExist:
        result_list = None
    return result_list
person Adam Nelson    schedule 05.03.2009