2010-01-25 4 views
5

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

Вот что я "хочу", чтобы увидеть:

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 

EDIT 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> 

ответ

1

Это делает то, что вы хотите?

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

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

+0

Неплохо! Я продолжаю получать ошибку: не удается разрешить ключевое слово 'dwarf_set' в поле. Возможные варианты: id, job, name Но я стараюсь разные вещи. – TheLizardKing

+0

Я чувствую, что это сработает, если моя модель Гнома была напрямую связана с моей карьерой, но я решил связать их с помощью моей модели работы, чтобы позволить изменить карьеру. – TheLizardKing

1

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

2

ORM Django не собирается делать это uber-simple. Простой способ сделать что-то вроде:

для карьеры в Career.objects.all():. career.dwarf_set.all() COUNT()

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

Вы можете попытаться ускорить это, используя Django's Aggregation feature, но я не совсем уверен, что он сделает то, что вам нужно. Вы должны взглянуть.

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