I have a model which looks like this:
class Category(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField()
parent = models.ForeignKey(
'categories.Category',
null=True,
blank=True,
on_delete=models.CASCADE,
related_name='categories'
)
basically, in the parent
field, it references itself. If a parent is set to None, it’s the root category.
I use it to build a hierarchy of categories.
What would be the most efficient way to:
- fetch all the objects through the hierarchy
- display them in a template?
For some reason, select_related
does not seem to lead to performance improvements here.
I also found this: How to recursively query in django efficiently?
But had a really hard time applying it to my example, because I still don’t really understand what’s going on. This was my result:
WITH RECURSIVE hierarchy(slug, parent_id) AS (
SELECT slug, parent_id
FROM categories_category
WHERE parent_id = '18000'
UNION ALL
SELECT sm.slug, sm.parent_id
FROM categories_category AS sm, hierarchy AS h
WHERE sm.parent_id = h.slug
)
SELECT * FROM hierarchy
Would appreciate any help.
Thanks!
2
Answers
One possible solution can be using https://django-mptt.readthedocs.io/en/latest/overview.html#what-is-django-mptt
You can use the django-mptt template tag as this:
There is a tutorial and more information in the library docs.
I had the same problem and ended up creating the following function that hits the database once, then sorts out the heirarchy and returns a dict:
Each
value
of the returned dict is a top-level Category object which has achildren
attribute.You can render it in the template by looping through the dict values. The following example will handle three levels of heirarchy:
If you need to render many levels of the heirarchy, you could consider using template recursion. Have a read of the following question and answers to determine if that might be suitable: Represent a tree of objects in Django template