2010-01-25 17 views
5

Estoy intentando crear una página de perfil que muestra la cantidad de enanos asignados a cada carrera correspondiente. Tengo 4 carreras, 2 trabajos dentro de cada una de esas carreras y, por supuesto, muchos enanos que tienen un solo trabajo. ¿Cómo puedo contar el número de enanos en cada una de esas carreras? Mi solución fue hacer un seguimiento de los nombres de las carreras en el HTML y hacer una consulta para cada carrera, pero eso parece una cantidad excesiva de consultas.Django: Múltiples COUNT de dos modelos de distancia

Esto es lo que "quiero" para ver:

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

Aquí es mis modelos. Agrego algo de complejidad al no conectar Carreras directamente a mi modelo de Enanos (se han conectado por sus trabajos).

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 mi punto de vista se ve algo como:

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

y la plantilla:

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

El error es:

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

SOLUCIÓN

vista:

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

plantilla:

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

solución aún mejor

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

No se olvide de from django.db.models import Count, Q

Lo que me gusta de la solución anterior es que no solo devuelve carreras que tienen enanos trabajando, sino incluso las carreras que no tienen ninguno, que fue el siguiente problema que encontré. Aquí está mi punto de vista para la integridad:

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

Respuesta

1

¿Hace esto lo que quiere?

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

Ahora cada career objeto debe tener una propiedad dwarf__count.

+0

¡No está nada mal! Continúo obteniendo el error: No puedo resolver la palabra clave 'dwarf_set' en el campo. Las opciones son: id, job, name Pero estoy intentando cosas diferentes. – TheLizardKing

+0

Creo que esto funcionaría si mi modelo de Enano estuviera directamente relacionado con mi modelo de Carrera, pero elegí conectar los dos a través de mi modelo de Trabajo para permitir la alteración de las carreras. – TheLizardKing

1

¿No puedes obtener un conteo agrupado por carrera? Y haz una combinación externa si necesitas las cero filas devueltas también.

2

El ORM de Django no va a hacer que esto sea súper simple. La forma más sencilla es hacer algo como:

de carrera en Career.objects.all():. career.dwarf_set.all() count()

que ejecutará 1 consulta para cada puesto de trabajo (O (n) complejidad).

Puede intentar acelerar eso usando Django's Aggregation feature, pero no estoy del todo seguro de si hará lo que necesita. Tendría que echar un vistazo.

La tercera opción es usar SQL personalizado, que hará el trabajo absolutamente. Solo tiene que escribirlo y mantenerlo a medida que su aplicación crece y cambia ...