Django ORM: подсчет подмножества связанных элементов

Я ищу способ аннотировать набор запросов с подсчетом подмножества связанных элементов. Ниже приведено подмножество моих моделей:

class Person(models.Model):
    Name = models.CharField(max_length = 255)
    PracticeAttended = models.ManyToManyField('Practice',
                                              through = 'PracticeRecord')

class Club(models.Model):
    Name = models.CharField(max_length = 255)
    Slug = models.SlugField()
    Members = models.ManyToManyField('Person')

class PracticeRecord(PersonRecord):
    Person = models.ForeignKey(Person)
    Practice = models.ForeignKey(Practice)

class Practice(models.Model):
    Club = models.ForeignKey(Club, default = None, null = True)
    Date = models.DateField()

Я хочу создать набор запросов, который аннотирует количество конкретных клубных тренировок, которые посещал человек. Я уже могу найти общее количество практик этого человека с запросом Person.objects.all().annotate(Count('PracticeRecord'))

Однако я хотел бы как-то аннотировать количество тренировок, которые человек посещает для конкретного клуба.

Я бы предпочел что-то с использованием ORM django, не прибегая к написанию необработанного SQL.

Спасибо.


person JudoWill    schedule 11.10.2010    source источник


Ответы (2)


Однако я хотел бы как-то аннотировать количество тренировок, которые человек посещает для конкретного клуба.

Покажи нам.

Сначала найдите конкретный клуб.

club = Club.objects.get(**conditions)

Далее отфильтруйте всех лиц, которые занимались в этом клубе.

persons = Person.objects.filter(practicerecord__Practice__Club = club)

Теперь аннотируйте с подсчетом.

q = persons.annotate(count = Count('practicerecord'))

Изменить

Мне удалось успешно выполнить эту работу в моей тестовой установке: Django 1.2.3, Python 2.6.4, Postgresql 8.4, Ubuntu Karmic.

PS. Рекомендуется использовать имена полей в нижнем регистре. Это значительно упрощает использование синтаксиса двойного подчеркивания (__) для связывания полей. Например, в вашем случае Django автоматически создает practicerecord для каждого Person. Когда вы пытаетесь получить доступ к другим полям PracticeRecord через это поле, вы должны помнить об использовании заглавных букв.

Если бы вы использовали имена в нижнем регистре, вы могли бы написать:

persons = Person.objects.filter(practicerecord__practice__club = club)
#                                               ^^        ^^  

который выглядит гораздо более однородным.

PPS: это Count('practicerecord') (обратите внимание на нижний регистр).

person Manoj Govindan    schedule 11.10.2010
comment
ВАУ, это круто и отлично работает... Я не знал, что если бы я отфильтровал по определенному полю, то агрегация также была бы по отфильтрованным строкам. Из любопытства, не знаете ли вы, упоминается ли это поведение где-либо в документах? - person JudoWill; 11.10.2010

Боюсь, здесь единственный вариант — это raw sql. В любом случае, это не так страшно и трудно управлять, если вы поставите его в менеджер моделей.

person Vladimir Sidorenko    schedule 11.10.2010
comment
Странный. Мне удалось заставить его работать, не прибегая к Raw SQL. Протестировано в Django 1.2.3, Postgresql 8.4, Python 2.6.4, Ubuntu Karmic. - person Manoj Govindan; 11.10.2010
comment
Да, есть способ аннотировать после фильтрации исходного набора запросов. Я думал, что задача состоит в том, чтобы аннотировать записи практики без фильтрации людей. - person Vladimir Sidorenko; 12.10.2010