castiel
castiel

Reputation: 2773

Django foreign key reverse set count

So, provided code like this:

class Category(models.Model):
    parent = models.ForeignKey('self', null=True, blank=True)
    name = models.CharField('name', max_length)

I might have a relationship like this: category_two's parent is category_one and category_three's parent is category two.

I want to filter out all the category that doesn't have children. this means like this:

category_three.category_set.count() == 0; # category_three has no children
category_two.category_set.count() != 0; # category_three's parent is category_two

But When I try this:

Category.objects.filter(category_set__count=0) # this is the wrong code that won't work
# this would actually gives out the following error message
#Cannot resolve keyword 'category_set' into field. Choices are: category, id, name, parent, parent_id

Basically what I want is filter out all the ending category, means the category that won't have any child.

Hope that I explained clearly. Any idea how to do this?

Upvotes: 2

Views: 1745

Answers (2)

knbk
knbk

Reputation: 53659

Use the __isnull lookup:

categories = Category.objects.filter(category__isnull=True)

In the context of a relationship, __isnull=True matches if there are no related objects, and __isnull=False matches if there is at least one related object. Alternatively, you can replace category__isnull=True with category=None, this will generate the same query.

Upvotes: 2

cziemba
cziemba

Reputation: 664

Try filtering on an annotation:

from django.db.models import Count

categories = Category.objects.annotate(num_children=Count('category_set')).filter(num_children__gt=0)

Annotating every category with a field of 'num_children' which is the count of the 'category_set' field and then filtering should get you only the categories that have children.

Upvotes: 3

Related Questions