Django упорядочивает элементы по двум полям, но игнорирует их, если они равны нулю

у меня есть следующая модель (значительно упрощенная для целей этого вопроса):

class Product(models.Model):
    price = models.DecimalField(max_digits=8, decimal_places=2)
    sale_price = models.DecimalField(max_digits=10, blank=True, null=True, decimal_places=2)

для большинства продуктов, цена будет заполнена, но sale_price не будет. Итак, я могу заказать продукцию по цене так:

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

однако некоторые продукты будут иметь sale_price, и я не могу найти способ заказать их аккуратно, чтобы цена продажи чередовалась с нормальной ценой. Если я попробую заказать по обоим полям:

Product.objects.order_by('sale_price','price')

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

имеет ли это смысл? У кого-нибудь есть способ решить эту проблему?

спасибо!

2 ответов


вы можете использовать метод extra() QuerySet для создания дополнительного поля в вашем запросе, используя функцию COALESCE в SQL, которая возвращает первое ненулевое значение, которое она передала.

Product.objects.extra(select={"current_price":"COALESCE(sale_price, price)"}, order_by=["-current_price"])

вы должны поместить свой order_by в вызов extra (), поскольку дополнительное ручное поле "на самом деле не существует", насколько это касается остальной части ORM, но синтаксис такой же, как обычный Django order_by () s.

см. дополнительную документацию () здесь: http://docs.djangoproject.com/en/1.3/ref/models/querysets/#extra


Если вы наткнетесь на это требование, и с помощью Джанго 1.8 и выше, вы можете использовать django.db.models.functions.Coalesce для немного приятнее, крест db-engine, решение:

from django.db.models.functions import Coalesce

Product.objects.annotate(
    current_price=Coalesce('sale_price', 'price')
).order_by('-current_price')