Django - Display child elements based on parent in ModelChoiceField queryset

I have created models that each of them based on own parent. On forms I have used ModelChoiceField. When the user selects the element from Category choice field, on Subcategory field should be displayed only its child elements. And also after selecting the Subcategory, on ProductCategory choice field should be displayed child elements.

it should have been something like this

But I am getting error: TypeError: Field 'id' expected a number but got <django.forms.models.ModelChoiceField object at 0x7f3d1f9f0ac0>. How can I improve it?

models.py:

class Category(models.Model):
    name = models.CharField("Category Name", max_length=100, unique=True)
    link = models.CharField("Category Link", max_length=250)

    def __str__(self):
        return self.name

class Subcategory(models.Model):
    parent = models.ForeignKey(Category, on_delete=models.CASCADE, null=True)
    name = models.CharField("Sub-category Name", max_length=100, unique=True)
    link = models.CharField("Sub-category Link", max_length=250)

    def __str__(self):
        return self.name

class ProductCategory(models.Model):
    parent = models.ForeignKey(Subcategory, on_delete=models.CASCADE, null=True)
    name = models.CharField("Product-Category Name", max_length=100, unique=True)
    link = models.CharField("Product-Category Link", max_length=250)

    def __str__(self):
        return self.name

class ProductSubCategory(models.Model):
    parent = models.ForeignKey(ProductCategory, on_delete=models.CASCADE, null=True)
    name = models.CharField("Product-Sub-Category Name", max_length=100, unique=True)
    link = models.CharField("Product-Sub-Category Name", max_length=250)

    def __str__(self):
        return self.name
 

forms.py

class CategoryForm(forms.Form):
    category = forms.ModelChoiceField(queryset=Category.objects.all())
    subcategory = forms.ModelChoiceField(queryset=Subcategory.objects.filter(parent=category))
    prodcategory = forms.ModelChoiceField(queryset=ProductCategory.objects.filter(parent=subcategory))

On views.py I am just running external script

def homepage(request):
    context = {}
    form = CategoryForm()
    context['form'] = form
    if request.GET:
        temp = request.GET['prodcategory']
        selected = ProductCategory.objects.get(pk=temp)
        scraper = Scraper()
        results = scraper.scrape(title=selected, link=selected.link)
        data = ProductSubCategory.objects.filter(parent=results)
        context['data'] = data
    return render(request, 'index.html', context)

There is a well explained article on how to approach chained drop down lists in Django forms :

How to Implement Dependent/Chained Dropdown List with Django

or you could use an external library like django-smart-selects

Back to Top