Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use ifnull default in django aggregation

I have the following model classes:

class Goods(models.Model):
    name = models.CharField(max_length=100)

class InRecord(models.Model):
    goods = models.ForeignKey(Goods, related_name='in_records')
    timestamp = models.DateTimeField()
    quantity = models.IntegerField()

class OutRecord(models.Model):
    goods = models.ForeignKey(Goods, related_name='out_records')
    timestamp = models.DateTimeField()
    quantity = models.IntegerField()

So, I want to get a QuerySet which contains all the goods having a positive repository.

Another way to describe it, I want to filter Goods which has a greater InRecord quantity summary than OutRecord summary.


What I've tried:

First, I use annotate to add the summary to the queryset:

qs = Goods.objects.annotate(
        qty_in=Sum(in_records__quantity), 
        qty_out=Sum(out_records_quantity)
    )

This seemed works, but have one problem, when there is no relative in_records or out_records of some goods, the fields annotated returns None.

Question: So, is there any way for me to set a default in this case, just like a ifnull(max(inreocrd.quantity), 0)* call in sql?


After this, I want to add a filter on that QuerySet:

I tried:

qs = qs.filter(qty_in__gt(F(qty_out)))

But still if there is no records on a goods, It doesn't work.

Please help.

like image 642
Alfred Huang Avatar asked Jan 19 '15 04:01

Alfred Huang


People also ask

Does Django ORM support subquery?

Django allows using SQL subqueries.

What is F in Django Queryset?

F() expressions. An F() object represents the value of a model field, transformed value of a model field, or annotated column. It makes it possible to refer to model field values and perform database operations using them without actually having to pull them out of the database into Python memory.

What is OuterRef in Django ORM?

to Django users. According to the documentation on models. OuterRef: It acts like an F expression except that the check to see if it refers to a valid field isn't made until the outer queryset is resolved.

What is Django aggregate?

When specifying the field to be aggregated in an aggregate function, Django will allow you to use the same double underscore notation that is used when referring to related fields in filters. Django will then handle any table joins that are required to retrieve and aggregate the related value.


1 Answers

You can use Django's Coalesce function. Something like this should work in Django 1.8 or later:

from django.db.models.functions import Coalesce

qs = Goods.objects.annotate(
        qty_in=Sum(Coalesce(in_records__quantity, 0)),
        qty_out=Sum(Coalesce(out_records__quantity, 0))
    )
like image 178
pdw Avatar answered Oct 03 '22 07:10

pdw