按升序排列 Django 查询集,但末尾为 0 值项

Order a Django queryset in ascending order but with 0-valued items at the end

我是 python、django 的新手。我想要做的是我有一个定义为产品的模型,它有两列:名称和价格。

name    price
pen      20
paper    30
eraser   0

我正在尝试使用以下代码对它们进行排序:

Product.objects.all().order_by('-price')

这会将值排序为 0,20,30

型号编码为

class Product(models.Model):
    name = models.CharField(max_length=100, blank=True, null=True)
    price = models.IntegerField('Price', blank=True, null=True)

我想要实现的是将其排序为 20,30,0,最后附加 0。

有什么功能可以实现吗?

以下可能可行,它不是最好的实现代码,但对于您的特殊情况,我认为这是直接使用查询集执行此操作的简单方法,否则您可以考虑在 Python(排序或其他内置函数)

qs = Product.objects.exclude(price=0).order_by('-price') | Product.objects.filter(price=0)

如果您真的想在数据库级别完成所有操作,您可以按计算值排序。这应该有效:

Product.objects.all().order_by(\
        Case(When(price=0, then=Value(MAX_INT)), default=F('price')))

其中 MAX_INT=2147483647 是 32 位有符号整数的值,即 safe on all Django-supported DBs

你想要实现的是这个SQL查询:

SELECT * FROM product ORDER BY price = 0, price;

使用 Django 的 ORM,使用 extra() 过滤器修饰符:

Product.objects.extra(select={"custom":"price = 0"}, order_by=["custom","price"]).all()

Conditional Expressions let you use if ... elif ... else logic within filters, annotations, aggregations, and updates. A conditional expression evaluates a series of conditions for each row of a table and returns the matching result expression.

from django.db.models import IntegerField, Case, Value, When

MAX_INT = 2147483647
Product.objects.annotate(
    my_price=Case(
        When(price=0, then=Value(MAX_INT)),
        default='price',
        output_field=IntegerField(),
    )
).order_by('my_price')

已编辑:根据@ivan 的回答和评论修复错误。