如何在使用distinct之后执行order_by?

时间:2017-01-17 15:12:29

标签: django python-3.x django-orm

在基于两个字段获取独特结果后,我想对结果进行排序。我遇到的问题是我不能在Django中使用两个ord​​er_by。 Django clears the previous order_by() whenever you use this function.

  

每个order_by()调用都将清除之前的任何排序。

模型示例:

class Product(models.Model):
    price = models.FloatField()
    name = models.CharField(max_length=100)
    group = models.CharField(max_length=100)

我想获得同一组中最低的产品。然后,我想按价格对它们进行排序。像这样:

Product.objects.order_by('group','price').distinct('group').order_by('price')
Product.objects.order_by('group','price').distinct('group').order_by('-price')

问题是,如果只是按照第一顺序使用,我会得到不同的产品。

-

修改

表格示例:

id | name | group | price
0  | aaa  | aaa   | 10.0
1  | aaa  | aaa   | 1.0
2  | aaa  | aaa   | 2.0
3  | aaa  | aaa   | 1.0
4  | bbb  | bbb   | 2.0
5  | bbb  | bbb   | 2.1
6  | bbb  | bbb   | 10.0

按价格排序:

1  | aaa  | aaa  | 1.0
4  | bbb  | bbb  | 2.0

按-price排序:

4  | bbb  | bbb  | 2.0
1  | aaa  | aaa  | 1.0

我遇到的问题是,当我使用order_by排序时,返回的产品会有所不同。

在sql语句中会是这样的:

SELECT * 
FROM product
WHERE id IN (
  SELECT DISTINCT ON 
  (group) id
  FROM product
  ORDER BY group ASC, price ASC
)
ORDER BY price DESC

我正在使用PostgreSQL

3 个答案:

答案 0 :(得分:2)

好的,这就是我的所作所为:

products = Product.objects.order_by('group','price').distinct('group')
result = Product.objects.filter(id__in=products).order_by('-price')

我不认为这是最有效的方式,但它正在发挥作用......

答案 1 :(得分:1)

我遇到了同样的问题并找到了另一种解决方案。在第一次请求使用sorted_by后跟不同的DB之后,您可以:

import operator

products = Product.objects.order_by('group','price').distinct('group')
result = sorted(products, key=operator.attrgetter('price'), reverse=True)

此解决方案更好,因为您没有向数据库发出第二个请求。

答案 2 :(得分:0)

我喜欢亚历山大使用排序的想法。我将排序后的函数放入models.QuerySet的子类中,然后相应地设置我的ProductManager。这使您可以将排序的方法链接到查询集上。

Gotcha::这将返回列表而不是查询集,因此排序后不能使用任何查询集方法。

相关模型字段排序:您可以通过使用点运算符(key ='price.other')传递跨查询的键来按相关模型字段进行排序

manager.py
class ProductQuerySet(models.QuerySet):
    def sorted(self, key, reverse=False):
        """ Returns a list (rather than queryset) of Djano model instances """
        return sorted(self, key=operator.attrgetter(key), reverse=reverse)

    def current(self):
        return self.order_by('group', 'price').distinct('group')

class ProductManagerBase(models.Manager):
   pass

ProductManager = ProductManagerBase.from_queryset(ProductQuerySet)

models.py
...
objects = ProductManager()

**查询

qs = (Product
     .current()
     .sorted('price', reverse=True))