database - objects - gte django
Trate NULL como ''0'' en el modelo de Django (2)
Uso el siguiente bit de código en mi aplicación Django:
pictures = gallery.picture_set.annotate( score=models.Sum( ''picturevote__value'' ) ).order_by( ''-score'' )
Hay una mesa de galerías. En cada uno de ellos hay algunas imágenes. Cuando un usuario vota hacia arriba o hacia abajo una imagen, se inserta una nueva fila en ''videovoto'' y se conecta a la imagen. Entonces puedo obtener el puntaje total de las imágenes. Ahora quiero ordenar las imágenes de una galería por sus valores de puntaje. Pero debido a que la mesa se une, puede haber el valor NULL para puntaje cuando no hubo ningún voto. Sin embargo, un puntaje de ''NULL'' se tratará como ''0''.
¿Algunas ideas?
editar: Bien, aquí hay alguna explicación adicional: el problema es que la agregación en el ejemplo anterior establece la score
en NULL. Cuando quiero mostrar el puntaje, uso algo como esto:
score = self.picturevote_set.aggregate( models.Sum( ''value'' ) )[ ''value__sum'' ] or 0
Luego, la agregación lleva a NULL (si no hay filas de picturevote) o un cierto valor. Si es NULL, la expresión-or lo convierte en un valor entero que se puede visualizar. Pero esto resuelve solo los problemas de visualización causados por el valor NULL. Cuando quiero ordenar las imágenes por este valor de score
como en el primer ejemplo de código, todas las entradas con NULL se ponen al final del conjunto de resultados ordenados. Primero hay imágenes con puntuaciones positivas, luego están las imágenes con valores negativos y ENTONCES hay imágenes que no se votaron arriba o abajo hasta el momento, porque tienen NULL como score
.
Mi pregunta es cómo se puede cambiar este comportamiento para que el orden sea correcto.
Antes de la introducción de las anotaciones, es posible que haya utilizado algo extra
para hacer algo como esto, que creo que debería devolver 0
en los casos en que no hay votos (si no lo hace para una implementación particular de la base de datos, puede al menos insertar directamente COALESCE
función COALESCE
necesaria - COALESCE(SUM(value), 0)
- utilizando este método):
pictures = gallery.picture_set.extra(
select={
''score'': ''SELECT SUM(value) FROM yourapp_picturevote WHERE yourapp_picturevote.picture_id = yourapp_picture.id'',
},
order_by=[''-score'']
)
No veo ninguna forma incorporada de agregar tu propio SQL a las nuevas anotaciones (que aún no he usado personalmente), pero parece que deberías poder crear una nueva anotación como esta:
from django.db.models import aggregates
from django.db.models.sql import aggregates as sql_aggregates
class SumWithDefault(aggregates.Aggregate):
name = ''SumWithDefault''
class SQLSumWithDefault(sql_aggregates.Sum):
sql_template = ''COALESCE(%(function)s(%(field)s), %(default)s)''
setattr(sql_aggregates, ''SumWithDefault'', SQLSumWithDefault)
Esto parece bastante feo, ya que necesita empaquetar el nuevo agregado en django.db.models.sql.aggregates
debido a la forma en que se django.db.models.sql.aggregates
las clases agregadas de SQL, pero todo lo que hemos hecho aquí se agrega un nuevo agregado que subclasifica Sum
, codificando una llamada a la función COALESCE
y agregando un marcador de posición para el valor predeterminado, que debe proporcionar como argumento de palabra clave (en este ejemplo de implementación muy básico, al menos).
Esto debería permitirle hacer lo siguiente:
pictures = gallery.picture_set.annotate(score=SumWithDefault(''picturevote__value'', default=0).order_by(''-score'')
Desde Django 1.8, hay una función de base de datos Coalesce
. Su consulta puede verse así:
from django.db.models.functions import Coalesce
score = self.picturevote_set.aggregate(Coalesce(models.Sum(''value''), 0))