Search code examples
djangodjango-select-relateddjango-related-manager

Django - how to control and filter related objects


I have two models

Note : there are some code i have removed to make the question simple

class Categories(models.Model):
    category_name           = models.CharField(max_length=100, null=True)

class Courses(models.Model):
    course_name             = models.CharField(max_length=200)
    category                = models.ForeignKey(Categories, on_delete = models.CASCADE,)

if i have for example 3 categories (PHP, Python, Javascript) and each one of this categories have a courses related to it like this

PHP = php_course1, php_course2, php_course3

Python = python_course1, python_course2, python_course3

Javascript = javascript_course1, javascript_course2, javascript_course3

So what i want when someone click on any category it will take him to another page which have only courses related to this category.

This what i have done to make this happen

views.py

class CategoriesListView(ListView):
   model               = Categories
   template_name       = 'category_list.html'
   context_object_name = 'category_list'

class CategoriesDetailView(DetailView):
   model               = Categories
   template_name       = 'category_detail.html'
   context_object_name = 'category_detail'

first template 'category_list.html'

{% for category in category_list %}

  <a href="{% url 'category' category.slug %}" class="btn">{{ category.category_name }}</a>

{% endfor %}

second template 'category_detail.html'

{% for course in category_detail.courses_set.all  %}

  <h1> {{ course.course_name }} </h1>

{% ednfor %}

this is work very well if i click on 'javascript category' for example it will show only 'javascript courses'.

The problem is i want to filter the courses but because i use related object like this make me don't have a context on the view so i can play with

so either the way i did is wrong that's why it's limit me and there is another good way which i want you to tell me about it or it is a good way and there is some thing that i can do to filter and play with 'courses' objects

I searched and found this but this give me all 'courses' not only the one that related to a particular 'Category'

def get_context_data(self, **kwargs):
    context = super(CategoriesDetailView, self).get_context_data(**kwargs)
    context['course'] = Courses.objects.all().select_related("category")
    return context

Solution

  • You have to filter the Courses model to get courses as per your category.

    You have to use a similar query in your view:

    def get_context_data(self, **kwargs):
        context = super(CategoriesDetailView, self).get_context_data(**kwargs)
        context['course'] = Courses.objects.filter() # Your filter query here
        return context
    

    Now your filter query can be based on the kwargs you're capturing the url.

    If you're capturing a slug, your filter query will be:

    slug = self.kwargs.get('slug')
    # assuming that you've a field called slug in Category model
    Courses.objects.filter(category__slug=slug)