Django упорядочивает элементы по двум полям, но игнорирует их, если они равны нулю - PullRequest
16 голосов
/ 14 мая 2011

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

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 ]

13 голосов
/ 14 мая 2011

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

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

12 голосов
/ 29 сентября 2015

Если вы сталкиваетесь с этим требованием и используете Django 1,8 и выше, вы можете использовать django.db.models.functions.Coalesce для более приятного решения с перекрестным дБ-движком:

from django.db.models.functions import Coalesce

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