[Django]-How to get all descendants of a node with Django treebeard?

2πŸ‘

I just had the same problem and figured out how to do it (consider it inside the function get_queryset of a ListView):

category = Category.objects.filter(slug=self.kwargs['category']).get()
descendants = list(category.get_descendants().all())
return self.model.objects.select_related('category').filter(category__in=descendants+[category, ])

Another option that I came up with was using a filter with β€˜OR’:

from django.db.models import Q

category = Category.objects.filter(slug=self.kwargs['category']).get()
descendants = list(category.get_descendants().all())
return self.model.objects.select_related('category').filter(Q(category__in=category.get_descendants()) | Q(category=category))
πŸ‘€Massa

2πŸ‘

I looked at the treebeard code to see how it gets descendants of a node. We can apply the same filters as a related field lookup.

paramcat = Category.objects.get(id=1) # how you actually get the category will depend on your application
#all items associated with this category OR its descendants:
items = Item.objects.filter(category__tree_id=paramcat.tree_id, category__lft__range=(paramcat.lft,paramcat.rgt-1))

I think using intermediate calls like get_descendants will result in one query per descendant, plus load all descendants into memory. It defeats the purpose of using treebeard in the first place

I’d be interested in seeing a custom lookup based on this code, I’m not sure how to do it…

πŸ‘€Simone

0πŸ‘

For example, you can get all descendants of a category with get_descendants() in views.py as shown below. *You can see my answer explaining how to get all descendants of a category including the model instance itself with get_descendants(include_self=True):

# "views.py"

from django.http import HttpResponse
from .models import Category, Product

def test(request):
    categories = Category.objects.get(name="Food").get_descendants()
    print(categories) 
    # <TreeQuerySet [<Category: Meat>, <Category: Fish>]>

    products = Product.objects.filter(category__in=categories)
    print(products)
    # <QuerySet [<Product: Beef>, <Product: Pork>, <Product: Salmon>

    return HttpResponse("Test")

Leave a comment