2012-06-05 76 views
1

我在我的models.py下面的模型结构,项目和优惠:Django的“额外”的查询

class Item(models.Model): 

    STATUS_CHOICES = (
     ('A', 'Active'), 
     ('C', 'Cancelled'), 
    ) 

    status = models.CharField(max_length=11, choices=STATUS_CHOICES) 
    target_amount = models.PositiveIntegerField() 
    ... 

class Offer(models.Model) 

    STATUS_CHOICES = (
     ('A', 'Active'), 
     ('C', 'Cancelled'), 
    ) 

    status = models.CharField(max_length=11, choices=STATUS_CHOICES) 
    amount = models.PositiveIntegerField() 
    item = models.ForeignKey(Item) 
    ... 

我想写我的views.py查询以获得每个项目下面:

  1. 的电流(活性)的总提供此项目
  2. 已针对此项目满足由优惠(靶的百分比,即/ TARGET_AMOUNT * 100 [由式(1)的总] )

我一直在试图与“额外”来实现这一如下(使用的是Postgres):

items = Item.objects.filter(status='A').extra(
    select={ 
     'total_amount' : 'select coalesce(sum(amount),0) from myapp_offer where myapp_offer.item_id = myapp_item.id and myapp_offer.status = \'A\'', 
     'percentage_met' : '(((select coalesce(sum(amount),0) from myapp_offer where myapp_offer.item_id = myapp_item.id and myapp_offer.status = \'A\')/target_amount) * 100)' 
    } 
) 

现在第一选择(total_amount)是否正常工作,并返回我的期望,但percentage_met始终为0任何人都可以帮我解答为什么?

编辑:应该提到,我希望能够在ORDER_BY percentage_met

回答

1

你不需要extra这一点。只需使用aggregation

from django.db.models import Sum 

items = Item.objects.filter(status='A').annotate(total_amount=Sum('offer__amount')) 

percentage_met是每个对象,不管怎么说,这样就可以只在您的模型的方法:

class Item(models.Model): 
    ... 
    @property 
    def percentage_met(self): 
     if hasattr(self, 'total_amount'): 
      return (self.total_amount/float(self.target_amount)) * 100 
     return None 
+0

这是真实的,但麻烦的是我想ORDER_BY percentage_met ..只是尝试这样做,我不似乎无法order_by财产:/ – JimJay

+0

好吧,不要担心..已经计算出如何使用sorted()按照http://stackoverflow.com/questions/981375/using-a- django-custom-model-method-property-in-order- – JimJay

1

我不认为上面的代码是得到最彻底的方法你想要的值,但是,假设它是 - 我怀疑你看到的问题实际上是SQL中的一个问题 - 一个int/int获取到最近的int,在这种情况下是零。总和肯定是一个整数;什么是target_amount,它来自哪里?它是一个int吗?

在Postgres里:

select 2/100; 
?column? 
---------- 
     0 
(1 row) 

如果是这样,投中的一个值:

select 2::numeric/100; 
?column?   
------------------------ 
0.02000000000000000000 
(1 row) 
+0

这正是问题所在,谢谢。再看一遍,虽然我会同意,我试图做到这一点的方式不干净,必须有一个更简单的方法... – JimJay