按模型的属性(不是字段)对 Django QuerySet 进行排序

Posted

技术标签:

【中文标题】按模型的属性(不是字段)对 Django QuerySet 进行排序【英文标题】:Sorting a Django QuerySet by a property (not a field) of the Model 【发布时间】:2011-05-09 17:05:28 【问题描述】:

一些代码和我的目标

我的(简化的)模型:

class Stop(models.Model):
    EXPRESS_STOP = 0
    LOCAL_STOP   = 1

    STOP_TYPES = (
        (EXPRESS_STOP, 'Express stop'),
        (LOCAL_STOP, 'Local stop'),
    )

    name = models.CharField(max_length=32)
    type = models.PositiveSmallIntegerField(choices=STOP_TYPES)
    price = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)

    def _get_cost(self):
        if self.price == 0:
            return 0
        elif self.type == self.EXPRESS_STOP:
            return self.price / 2
        elif self.type == self.LOCAL_STOP:
            return self.price * 2
        else:
            return self.price    
    cost = property(_get_cost)

我的目标:我想按cost 属性排序。我尝试了两种方法。

使用 order_by QuerySet API

Stops.objects.order_by('cost')

这产生了以下模板错误:

Caught FieldError while rendering: Cannot resolve keyword 'cost' into field.

使用 dictsort 模板过滤器

% with deal_items|dictsort:"cost_estimate" as items_sorted_by_price %

收到以下模板错误:

Caught VariableDoesNotExist while rendering: Failed lookup for key [cost] in u'Union Square'

所以...

我该怎么做呢?

【问题讨论】:

【参考方案1】:

使用QuerySet.extra()CASE ... END 定义一个新字段,并对其进行排序。

Stops.objects.extra(select='cost': 'CASE WHEN price=0 THEN 0 '
  'WHEN type=:EXPRESS_STOP THEN price/2 WHEN type=:LOCAL_STOP THEN price*2',
  order_by=['cost'])

那个,或者将其余返回的QuerySet转换成一个列表,然后在上面使用L.sort(key=operator.attrgetter('cost'))

【讨论】:

我喜欢你的第二种方法。但是,如果 cost 是相关模型的属性,我将如何排序?示例:在Stop 模型中,我们有pricing = models.ForeignKey(Pricing)costPricing 的属性。 key=lambda x: x.pricing.cost

以上是关于按模型的属性(不是字段)对 Django QuerySet 进行排序的主要内容,如果未能解决你的问题,请参考以下文章

属性是不是适用于 Django 模型字段?

在 django 中按模型字段的子字符串对对象进行排序

在 Django 中获取模型的字段

Django模板按“不相关”模型的字段排序

Django-filter:按模型属性过滤

Django:按文本字段的长度查找