Django mptt - Danh mục cha hiển thị tất cả sản phầm của danh mục con

Với hầu hết các hướng dẫn sử dụng django-mptt, danh mục sẽ chỉ hiển thị những sản phẩm được gán trực tiếp với nó. Nên có trường hợp danh mục cha thì không có sản phẩm, nhưng danh mục con thì có.
Nếu bạn muốn danh mục cha cũng hiển thị các sản phẩm của danh mục con cháu của nó, thì tiếp tục nhé.

Xem qua 1 chút models

#app/models.py
...
class Category(MPTTModel):
    parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
    name = models.CharField(_('name'), max_length=100, unique=True, help_text=_("Required and unique"))
    slug = models.SlugField(_('slug'), max_length=100, unique=True,)
    ....

class Product(models.Model):  # thêm các trường, chay migration database
    title = models.CharField(
        verbose_name=_("title"),
        help_text=_("Required"),
        max_length=200
    )
    slug = models.SlugField(max_length=200, unique=True)
    category = models.ForeignKey(Category, blank=True, null=True, on_delete=models.RESTRICT)
    ...

Chúng ta sẽ thêm truy vấn hiển thị tất cả sản phẩm vào chế độ xem, tệp views.py

# app/views.py 
...
class ItemsByCategoryView(ListView):
    template_name = 'category.html'
    model = Category

    def get_context_data(self, **kwargs):
        context = super(ItemsByCategoryView, self).get_context_data(**kwargs)
        context['category'] = Category.objects.all()
        # hiển thị sản phẩm của chính nó và danh mục con cháu
        context['product_all_cat'] = Product.objects.filter(category__in=self.category.get_descendants(include_self=True))

        return context

Hiển thị nó trong templates:

<!-- templates/category.html -->
    <ul>
        {% for pro in product_all_cat %}
            <li>
                {{ pro.title }} | {{ pro.category.name }} 
            </li>
        {% empty %}
            <li>No product</li>
        {% endfor %}
    </ul>