Django Mptt: filtering based on child category

75 Views Asked by At

I use django-mptt for Category model and I have Service model as well.

The problem:

  • I got all services associated to node category by clicking on a child category.

What I want:

  • I want to get all services associated to child category that I click. I believe I have to check it in an additional step in views (ServiceByCategoryListView). But I have no idea how to do that. Google doesn’t help me.
models.py

class Service(models.Model):
    name = models.CharField(max_length=255)
    slug = models.SlugField(max_length=255)
    description = models.TextField()
    preparation = models.TextField()
    price = models.CharField(max_length=10)
    available = models.BooleanField(default='True')
    category = TreeForeignKey('Category', on_delete=models.PROTECT, related_name='services')

    def __str__(self):
        return self.name
    
class Category(MPTTModel):
    name = models.CharField(max_length=255, unique=True)
    parent = TreeForeignKey('self', 
                            on_delete=models.PROTECT, 
                            null=True, 
                            blank=True, 
                            related_name='children',
                            db_index=True)
    slug = models.SlugField()

    class MPTTMeta:
        order_insertion_by = ['name']

    class Meta:
        unique_together = [['parent', 'slug']]

    def get_absolute_url(self):
        return reverse('services-by-category', kwargs={'slug': self.slug})
urls.py

urlpatterns = [
    path('', CategoryListView.as_view(), name='category-list'),
    path('<slug:slug>/', ServiceByCategoryListView.as_view(), name='services-by-category'),
]
views.py

class CategoryListView(ListView):
    model = Category
    template_name = 'main/category_list.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['services'] = Service.objects.all()
        return context


class ServiceByCategoryListView(ListView):
    model = Service
    context_object_name = 'services'
    template_name = 'main/service_list.html'
    

    def get_queryset(self):
        self.category = Category.objects.filter(parent=None).get(slug=self.kwargs['slug'])
        branch_categories = self.category.get_descendants(include_self=True)
        queryset = Service.objects.filter(category__in=branch_categories)
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['name'] = self.category
        return context

I tried to find a solution in django-mptt documentation but have no result. Also I tried to use Q objects but I was not able to find a correct solution as well.

1

There are 1 best solutions below

7
Nathan On

I'm not sure if I've understood the problem correctly, but if you want to have all the services associated with the child category you're clicking on, without the services of the category you're clicking on, you need to set include_self=False in the get_queryset of your ServiceByCategoryListView class.