Seleccionar valores distintos de un campo de tabla

104

Estoy luchando para entender el ORM de Django. Lo que quiero hacer es obtener una lista de valores distintos dentro de un campo en mi tabla ... el equivalente a uno de los siguientes:

SELECT DISTINCT myfieldname FROM mytable

(o alternativamente)

SELECT myfieldname FROM mytable GROUP BY myfieldname

Al menos me gustaría hacerlo a la manera de Django antes de recurrir a sql sin procesar. Por ejemplo, con una mesa:

id, calle, ciudad

1, calle principal, casco

2, otra calle, casco

3, Bibble Way, Leicester

4, de otra manera, Leicester

Calle principal 5, Londidium

Me gustaría conseguir:

Hull, Leicester, Londidium.

alj
fuente

Respuestas:

202

Di que tu modelo es 'Tienda'

class Shop(models.Model):
    street = models.CharField(max_length=150)
    city = models.CharField(max_length=150)

    # some of your models may have explicit ordering
    class Meta:
        ordering = ('city')

Dado que puede tener el atributo de Metaclase orderingestablecido, puede usarlo order_by()sin parámetros para borrar cualquier orden al usar distinct(). Consulte la documentación en order_by()

Si no desea que se aplique ningún orden a una consulta, ni siquiera el orden predeterminado, llame a order_by () sin parámetros.

y distinct()en la nota donde se analizan los problemas relacionados con el uso distinct()con los pedidos.

Para consultar su DB, solo tiene que llamar a:

models.Shop.objects.order_by().values('city').distinct()

Devuelve un diccionario

o

models.Shop.objects.order_by().values_list('city').distinct()

Éste devuelve un ValuesListQuerySetque puedes convertir en un list. También se pueden añadir flat=Truea values_listaplanar los resultados.

Ver también: Obtener valores distintos de Queryset por campo

jujule
fuente
29
En realidad eso funciona. ¡Sin embargo! No pude hacer que funcionara en todos mis modelos. Weidly, funcionó en algunos pero no en otros. Para aquellos que tienen un pedido Meta, no funciona. Por lo tanto, primero debe borrar el orden en el conjunto de consultas. models.Shop.objects.order_by (). values ​​('city').
different
2
Es importante tener en cuenta que en values_listrealidad no devuelve una lista. Devuelve algo así como un conjunto de consultas. Me pareció útil usar siempre list () alrededor de las llamadas de values_list.
dheerosaur
8
values_listdevuelve ValuesListQuerySet, que es un iterador. La conversión a la lista puede ser útil, pero también puede afectar el rendimiento cuando todas las filas deben evaluarse a la vez, especialmente con grandes conjuntos de datos.
Peter Kilczuk
3
La Meta: ordering = ()"característica" de django orm y objects.distinct()vs. objects.ordering().distinct()nos causó horas de confusión. Debe haber una calcomanía de advertencia de seguridad para el consumidor en ese producto;) Podemos instituir una política de atributos de no-meta-pedido para evitar que se rasque la cabeza en el futuro.
placas
Puede desactivar la Metaclase orderingy resolver problemas distinctutilizando order_by()sin parámetros. Está en los documentos de la API de QuerySet en order_by()" Si no desea que se aplique ningún orden a una consulta, ni siquiera el orden predeterminado, llame order_by()sin parámetros " .
Mark Mikofski
11

Además de la todavía muy relevante respuesta de jujule , me parece muy importante también tener en cuenta las implicaciones de order_by()en distinct("field_name")consultas. Sin embargo, esta es una característica exclusiva de Postgres.

Si está utilizando Postgres y define un nombre de campo para el que la consulta debe ser distinta, entonces order_by()debe comenzar con el mismo nombre de campo (o nombres de campo) en la misma secuencia (puede haber más campos después).

Nota

Cuando especifique nombres de campo, debe proporcionar un order_by () en el QuerySet, y los campos en order_by () deben comenzar con los campos en distintos (), en el mismo orden.

Por ejemplo, SELECT DISTINCT ON (a) le da la primera fila para cada valor en la columna a. Si no especifica un pedido, obtendrá una fila arbitraria.

Si desea, por ejemplo, extraer una lista de ciudades en las que sabe tiendas, el ejemplo de jujule debería adaptarse a esto:

# returns an iterable Queryset of cities.
models.Shop.objects.order_by('city').values_list('city', flat=True).distinct('city')  
ingofreyer
fuente
2

Por ejemplo:

# select distinct code from Platform where id in ( select platform__id from Build where product=p)
pl_ids = Build.objects.values('platform__id').filter(product=p)
platforms = Platform.objects.values_list('code', flat=True).filter(id__in=pl_ids).distinct('code')
platforms = list(platforms) if platforms else []
Roger Sodré
fuente