从表字段中选择不同的值

169

我很难理解Django的ORM。我想做的是在我的表格中获取一个字段中不同值的列表....相当于以下其中一种:

SELECT DISTINCT myfieldname FROM mytable
(或者另外一种选择)
SELECT myfieldname FROM mytable GROUP BY myfieldname

在使用原始的 SQL 之前,我至少希望按照 Django 的方式来完成它。 例如,有一个表:

id, street, city

1, Main Street, Hull

2, Other Street, Hull

3, Bibble Way, Leicester

4, Another Way, Leicester

5, High Street, Londidium

我想要得到:

Hull, Leicester, Londidium。

5个回答

304

假设你的模型名称是'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',)

如果你可能已经设置了Meta类的ordering属性(它是元组或列表),那么在使用distinct()时,可以使用不带参数的order_by()来清除任何排序。有关详细信息,请参阅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。 你也可以在values_list中添加flat=True来展平结果。

另请参阅:按字段获取查询集的唯一值


32
实际上那个方法是有效的。但是!我无法在所有模型上都使其工作。奇怪的是,它在某些模型上可以工作,但在其他模型上却不行。对于那些具有元数据排序的模型,它不起作用。因此,您必须首先清除查询集上的排序。 models.Shop.objects.order_by().values('city').distinct() - alj
4
需要注意的是,values_list 实际上并不返回一个列表。它返回类似于查询集的东西。我发现在调用 values_list 时始终使用 list() 是很有用的。 - dheerosaur
11
values_list 返回的是一个迭代器 ValuesListQuerySet。将其转换为列表可能很方便,但在需要一次性评估所有行的情况下,尤其是对于大型数据集,这样做也可能会影响性能。 - Peter Kilczuk
4
Django ORM中的“Meta:ordering =()”特性和objects.distinct()objects.ordering().distinct()之间的区别,让我们困惑了数小时。这个产品应该有一个消费者安全警告标签 ;) 为了避免将来的困扰,我们可能会实施不允许使用“Meta:ordering”属性的策略。 - hobs
1
您可以通过关闭Meta类的ordering属性,并使用没有参数的order_by()来解决与distinct相关的问题。在查询集API文档中,这些内容都在order_by()中说明:“如果您不想对查询应用任何排序,即使是默认排序,也请调用没有参数的order_by()方法。” - Mark Mikofski
显示剩余2条评论

29

除了仍然非常相关的jujule的回答,我认为也很重要的是要意识到order_by()对于distinct("field_name")查询的影响。 然而,这只是Postgres的特性!

如果您正在使用Postgres,并且定义了查询需要独特的字段名称,则order_by()需要以相同的字段名称(或字段名称)开始,顺序也必须相同(之后可能会有更多字段)。

注意

当您指定字段名称时,必须在QuerySet中提供order_by(),并且order_by()中的字段必须以与distinct()中的字段相同的顺序开始。

例如,SELECT DISTINCT ON (a) 会为列a中的每个值提供第一行。如果不指定顺序,将获得任意行。

如果您想例如提取一个您知道店铺所在城市的列表,则jujule的示例需要适应于此:

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

1
非常感谢您使用.distinct("field_name") - Denis

3

例如:

# 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
SELECT DISTINCT语句用于仅返回不同的值。在表内,一个列通常包含许多重复的值;使用distinct()函数,我们可以获得唯一的数据。

event = Event.objects.values('item_event_type').distinct()
serializer= ItemEventTypeSerializer(event,many=True)
return Response(serializer.data)


1
如果您使用PostgreSQL,并且只想获取并去重一个特定字段,则可以使用以下方法。
MyModel.objects.values('name').annotate(Count('id')).order_by()

这个查询集返回的是那些'name'字段唯一且具有相同名称行数的计数。
<QuerySet [{'name': 'a', 'id__count': 2}, {'name': 'b', 'id__count': 2}, {'name': 'c', 'id__count': 3}>

我知道返回的数据不完整,有时候也不令人满意,但有时候还是有用的。

文档参考


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接