Запрос Django (агрегаты и числа) - PullRequest
1 голос
/ 25 мая 2011

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

class Interaction(DateAwareModel, UserAwareModel):
  page = models.ForeignKey(Page)
  container = models.ForeignKey(Container, blank=True, null=True)
  content = models.ForeignKey(Content)
  interaction_node = models.ForeignKey(InteractionNode)
  kind = models.CharField(max_length=3, choices=INTERACTION_TYPES)

Я хочу иметь возможность сделать один запрос, чтобы получить количество взаимодействий, сгруппированных по контейнерам, а затем по видам.Идея состоит в том, что выходная структура данных JSON (сериализация, осуществляемая поршнем) будет выглядеть следующим образом:

"data": {
   "container 1": {
       "tag_count": 3, 
       "com_count": 1
   },
   "container 2": {
       "tag_count": 7, 
       "com_count": 12
   },
   ...
}

SQL будет выглядеть так:

SELECT container_id, kind, count(*) FROM rb_interaction GROUP BY container_id, kind;

Любые идеи поКак сгруппировать по нескольким полям, используя ORM?(Я не хочу писать необработанные запросы для этого проекта, если могу избежать идентификатора.) Это кажется простым и распространенным запросом.

Прежде чем вы спросите: я видел документацию по агрегатам django и документацию по необработанным запросам.

Обновление В соответствии с приведенным ниже советом, я создал специальный менеджер для обработки этого:

class ContainerManager(models.Manager):
    def get_query_set(self, *args, **kwargs):
        qs = super(ContainerManager, self).get_query_set(*args, **kwargs)
        qs.filter(Q(interaction__kind='tag') | Q(interaction__kind='com')).distinct()
        annotations = {
            'tag_count':models.Count('interaction__kind'),
            'com_count':models.Count('interaction__kind')
        }
        return qs.annotate(**annotations)

Считает только те взаимодействия, которые имеют вид tag или com.вместо того, чтобы получать количество тегов и com через группу по.Очевидно, что это работает так из кода, но интересно, как это исправить ...

1 Ответ

2 голосов
/ 25 мая 2011

Создайте собственный менеджер:

class ContainerManager(models.Manager):
    def get_query_set(self, *args, **kwargs):
        qs = super(ContainerManager, self).get_query_set(*args, **kwargs)
        annotations = {'tag_count':models.Count('tag'), 'com_count':models.Count('com')}
        return qs.annotate(**annotations)

class Container(models.Model):
    ...
    objects = ContainerManager()

Тогда Container запросы всегда будут включать атрибуты tag_count и com_count.Вам, вероятно, придется изменить аннотации, поскольку у меня нет копии вашей модели, на которую можно сослаться;Я только угадал имена полей.

ОБНОВЛЕНИЕ:

Так что после лучшего понимания ваших моделей, аннотации не будут работать для того, что вы ищете,Действительно, единственное, что нужно подсчитать, сколько Container s имеет kind s 'tag' или 'com':

tag_count = Container.objects.filter(kind='tag').count()
com_count = Container.objects.filter(kind='com').count()

Аннотации не дадут вам эту информацию.Я думаю, что можно написать свои собственные агрегаты и аннотации, так что это может быть возможным решением.Тем не менее, я никогда не делал этого сам, поэтому я не могу дать вам какие-либо указания там.Вы, вероятно, застряли с использованием прямого SQL.

...