【问题标题】:Select DISTINCT individual columns in django?在 django 中选择 DISTINCT 个别列?
【发布时间】:2011-04-20 14:35:38
【问题描述】:

我很好奇是否有任何方法可以在 Django 中进行查询,而不是下面的“SELECT * FROM...”。我正在尝试改用“SELECT DISTINCT columnName FROM ...”。

具体来说,我有一个看起来像这样的模型:

class ProductOrder(models.Model):
   Product  = models.CharField(max_length=20, promary_key=True)
   Category = models.CharField(max_length=30)
   Rank = models.IntegerField()

其中RankCategory 中的等级。我希望能够遍历所有类别,对该类别中的每个等级进行一些操作。

我想首先获取系统中所有类别的列表,然后查询该类别中的所有产品并重复,直到处理完每个类别。

我宁愿避免使用原始 SQL,但如果我必须去那里,那很好。虽然我以前从未在 Django/Python 中编写过原始 SQL。

【问题讨论】:

    标签: django django-models distinct django-queryset django-orm


    【解决方案1】:

    其实很简单如果您使用的是 PostgreSQL,只需使用distinct(columns) (documentation)。

    Productorder.objects.all().distinct('category')
    

    请注意,此功能自 1.4 以来已包含在 Django 中

    【讨论】:

    • @lazerscience, @Manoj Govindan:对不起,你是对的。看来我已经修补了 Django 以添加该功能。我添加了补丁链接
    • 现在在 Django SVN 中,将在 Django 1.4 中
    • 注意:除非你使用 PostgreSQL,否则你不能给 distinct() 一个参数。最好坚持上述公认的解决方案。
    • 在测试中,这是 can_distinct_on_fields,似乎是 Postgres-only
    • 加1,但这里不需要all()
    【解决方案2】:

    从数据库中获取不同列名列表的一种方法是将distinct()values() 结合使用。

    在您的情况下,您可以执行以下操作来获取不同类别的名称:

    q = ProductOrder.objects.values('Category').distinct()
    print q.query # See for yourself.
    
    # The query would look something like
    # SELECT DISTINCT "app_productorder"."category" FROM "app_productorder"
    

    这里有几件事要记住。首先,这将返回一个ValuesQuerySet,其行为与QuerySet 不同。当您访问q(上图)的第一个元素时,您将获得一个字典,而不是ProductOrder 的实例。

    其次,最好阅读文档中关于使用distinct()warning note。上面的例子可以工作,但distinct()values() 的所有组合都可能不行。

    PS:最好对模型中的字段使用小写名称。在您的情况下,这意味着重写您的模型,如下所示:

    class ProductOrder(models.Model):
        product  = models.CharField(max_length=20, primary_key=True)
        category = models.CharField(max_length=30)
        rank = models.IntegerField()
    

    【讨论】:

    • 下面描述的方法现在在 django 1.4 中可用,如果您需要具有不同字段感知的 ProductOrder 实例,这很好;-)
    • 我想知道如何修改此代码,以便它也适用于where 语句。喜欢select distinct(app_productorder.category) from app_productorder where app_productorder.rank <30;
    • 如何将其转换为普通查询集?
    【解决方案3】:

    其他答案都很好,但这更简洁一些,因为它只给出了从 DISTINCT 查询中获得的值,而没有来自 Django 的任何内容。

    >>> set(ProductOrder.objects.values_list('category', flat=True))
    {u'category1', u'category2', u'category3', u'category4'}
    

    >>> list(set(ProductOrder.objects.values_list('category', flat=True)))
    [u'category1', u'category2', u'category3', u'category4']
    

    而且,它可以在没有 PostgreSQL 的情况下工作。

    这比使用 .distinct() 效率低,假设数据库中的 DISTINCT 比 python set 快,但它非常适合在 shell 周围闲逛。

    更新: 这个答案非常适合在开发期间在 Django shell 中进行查询。不要在生产中使用此解决方案,除非您绝对确定在应用 set 之前您将始终获得少量结果。否则,从性能的角度来看,这是一个糟糕的主意。

    【讨论】:

    • values_list 没有将DISTINCT 放在sql查询中,所以如果有的话,这会带来多个值。
    • 从性能的角度来看这是一个糟糕的主意!
    • 是的——如果你有一张非小桌子,不要在生产中这样做!
    【解决方案4】:

    用户使用该字段排序,然后进行区分。

    ProductOrder.objects.order_by('category').values_list('category', flat=True).distinct()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-08
      • 1970-01-01
      • 1970-01-01
      • 2010-11-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-08
      • 1970-01-01
      相关资源
      最近更新 更多