urls template examples example bootstrap django sql-order-by nullable

template - Django: ordena por posición ignorando NULL



views django example (6)

Tengo un problema con el orden django queryset.

Mi modelo contiene un campo llamado position (un PositiveSmallIntegerField ), que me gustaría utilizar para ordenar los resultados de la consulta.

Uso order_by(''position'') , que funciona muy bien.

Problema : mi campo de position es null=True, blank=True ( null=True, blank=True ), porque no quiero especificar una posición para cada 50000 instancias de mi modelo :(

Cuando algunas instancias tienen una "posición" order_by , order_by devuelve en la parte superior de la lista: me gustaría que estén al final ...

En SQL RAW, solía escribir cosas como " IF(position IS NULL or position='''', 1, 0) " (ver http://www.shawnolson.net/a/730/mysql-sort-order-with-null.html ): ¿es posible obtener el mismo resultado usando Django, sin escribir SQL sin formato?

Muchas gracias !


A partir de Django 1.8, puede usar Coalesce() para convertir NULL a 0 .

Muestra:

import datetime from django.db.models.functions import Coalesce, Value from app import models # Coalesce works by taking the first non-null value. So we give it # a date far before any non-null values of last_active. Then it will # naturally sort behind instances of Box with a non-null last_active value. the_past = datetime.datetime.now() - datetime.timedelta(days=10*365) boxes = models.Box.objects.all().annotate( new_last_active=Coalesce( ''last_active'', Value(the_past) ) ).order_by(''-new_last_active'')


Descubrí que la sintaxis de la respuesta de Pablo debía actualizarse a la siguiente en mi instalación 1.7.1:

items = Item.objects.all().extra(select={''null_position'': ''CASE WHEN {name of Item''s table}.position IS NULL THEN 0 ELSE 1 END''}).order_by(''-null_position'', ''position'')


Es una pena que haya muchas preguntas como esta en SO que no están marcadas como duplicadas. Vea (por ejemplo) esta respuesta para la solución nativa para Django 1.11 y más reciente. Aquí hay un breve extracto:

Se agregaron los parámetros nulls_first y nulls_last a Expression.asc () y desc () para controlar el orden de los valores nulos.

Ejemplo de uso (del comentario a esa respuesta):

from django.db.models import F MyModel.objects.all().order_by(F(''price'').desc(nulls_last=True))

El crédito va al autor de la respuesta original y al comentarista.


Puede usar la anotación () de django agrregation para hacer el truco:

items = Item.objects.all().annotate(null_position=Count(''position'')).order_by(''-null_position'', ''position'')


Usar extra () como dice Ignacio optimiza mucho la consulta final. En mi aplicación, he guardado más de 500ms (eso es mucho para una consulta) en el procesamiento de la base de datos usando extra () en lugar de anotar ()

Así es como se vería en su caso:

items = Item.objects.all().extra( ''select'': { ''null_position'': ''CASE WHEN {tablename}.position IS NULL THEN 0 ELSE 1 END'' } ).order_by(''-null_position'', ''position'')

{tablename} debería ser algo así como {Item''s app} _item siguiendo el nombre de las tablas predeterminadas de django.


QuerySet.extra() se puede usar para inyectar expresiones en la consulta y ordenarlas.