[Django]-How can I get a total count of a model's related objects and the model's children's related objects?

3πŸ‘

βœ…

I think the most efficient way of calculating this is at write time. You should modify OrganizationalUnit like this:

class OrganizationalUnit(models.Model):
    name = models.CharField(max_length=100)
    parent = models.ForeignKey(
        'self',
        blank=True, null=True,
        related_name='children',
    )
    checkout_number = models.IntegerField(default=0)

create the functions that will update the OrganizationalUnit and its parents at write time:

def pre_save_checkout(sender, instance, **kwargs):
    if isinstance(instance,Checkout) and instance.id and instance.department:
         substract_checkout(instance.department)

def post_save_checkout(sender, instance, **kwargs):
    if isinstance(instance,Checkout) and instance.department:
         add_checkout(instance.department)

def  substract_checkout(organizational_unit):
    organizational_unit.checkout_number-=1
    organizational_unit.save()
    if organizational_unit.parent:
        substract_checkout(organizational_unit.parent)

def  add_checkout(organizational_unit):
    organizational_unit.checkout_number+=1
    organizational_unit.save()
    if organizational_unit.parent:
        add_checkout(organizational_unit.parent)

now all you need is connect those functions to the pre_save, post_save and pre_delete signals:

from django.db.models.signals import post_save, pre_save, pre_delete

pre_save.connect(pre_save_checkout, Checkout)
pre_delete.connect(pre_save_checkout, Checkout)
post_save.connect(post_save_checkout, Checkout)

That should do it…

πŸ‘€Julian

3πŸ‘

What you need is a recursive function that traverse OrganizationalUnit relation tree and gets number of related Checkouts for each OrganizationalUnit. So your code will look like this:

def count_checkouts(ou):
   checkout_count = ou.checkouts.count()
   for kid in ou.children.all():
       checkout_count += count_checkouts(kid)
   return checkout_count

Also note, that to get a number of related checkouts I use:

checkout_count = ou.checkouts.count()

insted of:

count = ou.checkouts.all().count()

My variant is more efficient (see http://docs.djangoproject.com/en/1.1/ref/models/querysets/#count).

πŸ‘€Bohdan

0πŸ‘

I’m not sure how does SQL perform on this one but what you want to do is exactly what you explained.

Get all OU and it’s parents with While loop and then count Checkouts and sum them.

ORM brings you dynamic operations over SQL but kill performance:)

πŸ‘€iElectric

Leave a comment