web-dev-qa-db-fra.com

Sélectionner des valeurs distinctes dans un champ de table

J'ai du mal à comprendre le ORM de Django. Ce que je veux faire, c'est obtenir une liste de valeurs distinctes dans un champ de ma table ... équivalent à l'un des éléments suivants:

SELECT DISTINCT myfieldname FROM mytable

(Ou bien)

SELECT myfieldname FROM mytable GROUP BY myfieldname

Je voudrais au moins le faire de la manière Django avant de recourir au sql brut. Par exemple, avec une table:

id, rue, ville

1, rue principale, Hull

2, autre rue, Hull

3, façon Bibble, Leicester

4, autrement, Leicester

5, rue principale, Londidium

J'aimerais avoir:

Hull, Leicester, Londidium.

84
alj

Dites que votre modèle est 'Shop'

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')

Puisque vous pouvez avoir l'attribut Meta class ordering, vous pouvez utiliser order_by() sans paramètres pour effacer tout ordre lorsque vous utilisez distinct(). Voir la documentation sous order_by ()

Si vous ne souhaitez appliquer aucun ordre à une requête, même à l'ordre par défaut, appelez order_by () sans paramètre.

et distinct() dans la note où sont abordés les problèmes d'utilisation de distinct() avec la commande.

Pour interroger votre base de données, il vous suffit d'appeler:

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

Il retourne un dictionnaire

ou

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

Celui-ci retourne un ValuesListQuerySet que vous pouvez convertir en un list. Vous pouvez également ajouter flat=True À values_list Pour aplatir les résultats.

Voir aussi: Obtenir les valeurs distinctes de Queryset par champ

174
jujule

En plus des réponses très pertinentes réponse de jujule , je trouve assez important d’être également conscient des implications des requêtes order_by() sur distinct("field_name"). Ceci est cependant une fonctionnalité uniquement postgres!

Si vous utilisez Postgres et si vous définissez un nom de champ pour lequel la requête doit être distincte, alors order_by() doit commencer par le même nom de champ (ou noms de champs) dans la même séquence (il peut y avoir plus de champs après).

Remarque

Lorsque vous spécifiez les noms de champ, vous devez fournir order_by () dans le QuerySet, et les champs de order_by () doivent commencer par les champs de distinct (), dans le même ordre.

Par exemple, SELECT DISTINCT ON (a) vous donne la première ligne pour chaque valeur de la colonne a. Si vous ne spécifiez pas d'ordre, vous obtiendrez une ligne arbitraire.

Si vous voulez extraire une liste de villes dans lesquelles vous connaissez des boutiques, vous devez adapter l'exemple de Jujule à ceci:

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

Par exemple:

# 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 []
2
Roger Sodré