Джанго: несколько COUNT от двух моделей - PullRequest
5 голосов
/ 25 января 2010

Я пытаюсь создать страницу профиля, которая показывает количество гномов, назначенных для каждой соответствующей карьеры. У меня есть 4 карьеры, 2 работы в каждой из этих профессий и, конечно, много гномов, у каждого из которых есть одна работа. Как я могу подсчитать количество гномов в каждой из этих карьер? Мое решение состояло в том, чтобы жестко связать названия профессий в HTML и сделать запрос для каждой профессии, но это кажется чрезмерным количеством запросов.

Вот что я «хочу» увидеть:

Unassigned: 3
Construction: 2
Farming: 0
Gathering: 1

Вот мои модели. Я добавляю некоторую сложность, не подключая Карьеры напрямую к моей модели Гномов (они связаны своими работами).

from django.contrib.auth.models import User
from django.db import models

class Career(models.Model):
    name = models.CharField(max_length = 64)

    def __unicode__(self):
        return self.name

class Job(models.Model):
    career = models.ForeignKey(Career)
    name = models.CharField(max_length = 64)
    career_increment = models.DecimalField(max_digits = 4, decimal_places = 2)
    job_increment = models.DecimalField(max_digits = 4, decimal_places = 2)

    def __unicode__(self):
        return self.name

class Dwarf(models.Model):
    job = models.ForeignKey(Job)
    user = models.ForeignKey(User)
    created = models.DateTimeField(auto_now_add = True)
    modified = models.DateTimeField(auto_now = True)
    name = models.CharField(max_length = 64)

    class Meta:
        verbose_name_plural = 'dwarves'

    def __unicode__(self):
        return self.name

РЕДАКТИРОВАТЬ 1 мой взгляд выглядит примерно так:

def fortress(request):
    careers = Career.objects.annotate(Count('dwarf_set'))
    return render_to_response('ragna_base/fortress.html', {'careers': careers})

и шаблон:

{% for career in careers %}
    <li>{{ career.dwarf_set__count }}</li>
{% endfor %}

Ошибка:

Cannot resolve keyword 'dwarf_set' into field. Choices are: id, job, name

РЕШЕНИЕ

вид:

def fortress(request):
    careers = Career.objects.all().annotate(dwarfs_in_career = Count('job__dwarf'))
    return render_to_response('ragna_base/fortress.html', {'careers': careers})

шаблон:

{% for career in careers reversed %}
    <li>{{ career.name }}: {{ career.dwarves_in_career }}</li>
{% endfor %}

ДАЖЕ ЛУЧШЕЕ РЕШЕНИЕ

careers = Career.objects.filter(Q(job__dwarf__user = 1) | Q(job__dwarf__user__isnull = True)) \
    .annotate(dwarves_in_career = Count('job__dwarf'))

Не забудьте from django.db.models import Count, Q

Что мне нравится в вышеупомянутом решении, так это то, что он возвращает не только карьеру, в которой работают дварфы, но даже карьеру, в которой нет ни одной, что было следующей проблемой, с которой я столкнулся. Вот мой взгляд на полноту:

<ul>
{% for career in careers %}
    <li>{{ career.name }}: {{ career.dwarves_in_career }}</li>
{% endfor %}
</ul>

Ответы [ 3 ]

2 голосов
/ 25 января 2010

ORM в Django не сделает это слишком простым. Простой способ сделать что-то вроде:

за карьеру в Career.objects.all (): career.dwarf_set.all (). Count ()

Это выполнит 1 запрос для каждого задания (O (n) сложность).

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

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

1 голос
/ 25 января 2010

Делает ли это то, что вы хотите?

from django.db.models import Count
Career.objects.annotate(Count('dwarf'))

Теперь каждый career объект должен иметь свойство dwarf__count.

1 голос
/ 25 января 2010

Разве вы не можете просто получить счет, сгруппированный по карьере? И сделайте внешнее соединение, если вам нужно вернуть также нулевые строки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...