Выберите отдельные значения из поля таблицы

105

Я изо всех сил пытаюсь понять ORM Django. Я хочу получить список различных значений в поле в моей таблице ... эквивалент одного из следующих:

SELECT DISTINCT myfieldname FROM mytable

(или альтернативно)

SELECT myfieldname FROM mytable GROUP BY myfieldname

Я бы по крайней мере хотел сделать это способом Django, прежде чем прибегать к raw sql. Например, со столом:

id, улица, город

1, Main Street, Hull

2, Другая улица, Корпус

3, Bibble Way, Лестер

4, Другой путь, Лестер

5, Хай-стрит, Лондон

Я хочу получить:

Халл, Лестер, Лондидиум.

alj
источник

Ответы:

206

Скажите, что ваша модель "Магазин"

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

Поскольку у вас может быть установлен атрибут Metaclass ordering, вы можете использовать order_by()без параметров, чтобы очистить любой порядок при использовании distinct(). См. Документацию в разделе order_by()

Если вы не хотите, чтобы к запросу применялось какое-либо упорядочение, даже упорядочение по умолчанию, вызовите order_by () без параметров.

и distinct()в примечании, где обсуждаются вопросы использования distinct()с заказом.

Чтобы запросить вашу БД, вам просто нужно позвонить:

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

Возвращает словарь

или

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

Этот возвращает, ValuesListQuerySetкоторый вы можете преобразовать в list. Вы можете также добавить flat=Trueк values_listвыравниваться результаты.

См. Также: Получение различных значений Queryset by field

джуджуле
источник
29
На самом деле это работает. Тем не мение! Я не мог заставить его работать на всех моих моделях. Вейдли, это сработало на некоторых, но не на других. Для тех, у кого есть мета-порядок, это не работает. Итак, вам нужно сначала очистить порядок в наборе запросов. models.Shop.objects.order_by (). values ​​('city').
independent
2
Важно отметить, что на values_listсамом деле это не возвращает список. Он возвращает что-то вроде набора запросов. Я счел полезным всегда использовать list () вокруг вызовов values_list.
динозавр
8
values_listвозвращает ValuesListQuerySet, который является итератором. Приведение к списку может быть удобным, но также может снизить производительность, когда все строки должны быть оценены одновременно, особенно с большими наборами данных.
Петр Кильчук
3
Meta: ordering = ()«Особенность» Джанго ОРМ и objects.distinct()VS. objects.ordering().distinct()вызывает у нас часов путаницы. На этом продукте должна быть наклейка с предупреждением о безопасности потребителей;) Мы можем ввести политику отсутствия атрибутов мета-заказа, чтобы предотвратить царапины на голове в будущем.
hobs
Вы можете отключить Metaкласс orderingи решить проблемы с distinctиспользованием order_by()без параметров. Это в документации QuerySet API под order_by()« Если вы не хотите какой - либо заказ будет применяться к запросу, даже не упорядоченности по умолчанию, вызов order_by()без параметров. »
Марк Mikofski
11

Помимо еще очень актуальных ответу jujule , я считаю , это очень важно также знать о последствиях order_by()на distinct("field_name")запросах. Однако это только функция Postgres!

Если вы используете Postgres и определяете имя поля, для которого запрос должен отличаться, тогда order_by()необходимо начинать с того же имени поля (или имен полей) в той же последовательности (после этого может быть больше полей).

Заметка

Когда вы указываете имена полей, вы должны указать order_by () в QuerySet, а поля в order_by () должны начинаться с полей в отличном () в том же порядке.

Например, SELECT DISTINCT ON (a) дает вам первую строку для каждого значения в столбце a. Если вы не укажете порядок, вы получите произвольную строку.

Если вы хотите, например, извлечь список городов, в которых вы знаете магазины, пример джужуле необходимо адаптировать к этому:

# returns an iterable Queryset of cities.
models.Shop.objects.order_by('city').values_list('city', flat=True).distinct('city')  
Ingofreyer
источник
2

По примеру:

# 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 []
Роджер Содре
источник