2009-01-24 10 views
26

Digamos que tengo el siguiente modelo:Solicitar un QuerySet por valor de campo agregado

class Contest: 
    title = models.CharField(max_length = 200) 
    description = models.TextField() 

class Image: 
    title = models.CharField(max_length = 200) 
    description = models.TextField() 
    contest = models.ForeignKey(Contest) 
    user = models.ForeignKey(User) 

    def score(self): 
     return self.vote_set.all().aggregate(models.Sum('value'))[ 'value__sum' ] 

class Vote: 
    value = models.SmallIntegerField() 
    user = models.ForeignKey(User) 
    image = models.ForeignKey(Image) 

Los usuarios de un sitio pueden contribuir con sus imágenes a varios concursos. Luego, otros usuarios pueden votar hacia arriba o hacia abajo. Todo funciona bien, pero ahora quiero mostrar una página en la que los usuarios puedan ver todas las contribuciones a un determinado concurso. Las imágenes se ordenarán por su puntuación. Por lo tanto He intentado lo siguiente:

Contest.objects.get(pk = id).image_set.order_by('score') 

Como temía que no funciona ya 'puntuación' hay un campo de base de datos que podría ser utilizado en las consultas.

Respuesta

47

Oh, por supuesto, me olvido de la nueva compatibilidad de agregación en Django y su funcionalidad annotate.

Así consulta puede tener este aspecto:

Contest.objects.get(pk=id).image_set.annotate(score=Sum('vote__value')).order_by('score') 
+0

¡Gran solución! :) – okoman

+0

Estoy obteniendo los resultados desordenados ... están en su mayoría en orden, pero algunos de ellos están fuera de lugar ... ¿qué podría causar eso? – Jiaaro

+0

Esta es la solución solo para ese caso específico, y no para el título de la pregunta: "QuerySet order by method". Esta NO es la solución para pedir un conjunto de preguntas por método: @ S.Lott response es la solución correcta para el caso genérico –

9

Puedes escribir tu propio tipo en Python de manera muy simple.

def getScore(anObject): 
    return anObject.score() 
objects= list(Contest.objects.get(pk = id).image_set) 
objects.sort(key=getScore) 

Esto funciona bien porque hemos ordenado la lista, que vamos a proporcionar a la plantilla.

+0

Sí, se puede. Solo haces la suma como parte de la consulta. –

+0

El objeto 'RelatedManager' no tiene ningún atributo 'sort' :( – okoman

+2

@okoman ... eso significa que no se convirtió a una lista usando la función list() – Jiaaro

1

El nivel-db order_by no puede ordenar el conjunto de preguntas por el método Python del modelo.

La solución es introducir el campo score en el modelo Image y volver a calcularlo en cada actualización Vote. Algún tipo de desnormalización Cuando puedas, puedes ordenarlo por él.

+0

No estoy seguro de que sea la * mejor * solución, pero es una * solución * –

+0

Oh, sí. Estoy de acuerdo. –

Cuestiones relacionadas