Search code examples
djangodjango-querysetdjango-aggregation

Apply condition in this query in django


I have models like this:

class Category(models.Model):

    user = models.ForeignKey(User)
    name = models.CharField(max_length=128)
    budget = models.DecimalField(default=0.0, decimal_places=2, max_digits=8, help_text="Amount in dollars ($)")

class Task(models.Model):

    description = models.CharField(max_length=128)
    owner = models.ForeignKey(User, default="bride")
    category = models.ForeignKey(Category)
    cost = models.DecimalField(default=0.0, decimal_places=2, max_digits=6, help_text="Amount in dollars ($)")

I want to find sum of all the budgets of each category and show remaining budget:

categories = Category.objects.filter(user_id=request.user.id).order_by("name")
categories_cost = [Task.objects.filter(category=i).aggregate(Sum('cost')) for i in categories]

category_budget = [i.budget for i in categories]

categories = zip(categories, remaining_budget)

Some categories may not have task yet. Thus, categories_cost would look like this:

[{'cost__sum': None}, {'cost__sum': Decimal('0.00')}, {'cost__sum': None}, {'cost__sum': Decimal('300.00')}]

So when I try to subtract I get this error:

>>> remaining_budget = [i.budget - j['cost__sum'] for i, j in zip(categories, rem)]
Traceback (most recent call last):
  File "<console>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'Decimal' and 'NoneType'

How to solve this?


Solution

  • There are many solutions. This is the simplest:

    remaining_budget = [i.budget - (j['cost__sum'] or 0) for i, j in zip(categories, rem)]
    

    or using map:

    rem = map(lambda x: (x or 0), rem)
    

    or using filter:

    def no_nones(item):
        if item is None:
            return 0
        return item
    
    rem = filter(no_nones, rem)