Search code examples
pythonajaxdjangodjango-smart-selects

django smart-selects ajax configuration


So I have finally implemented smart-selects (https://github.com/digi604/django-smart-selects) on the admin side, but now when I try to get the actual filters to work on the user side, the filters don't work. I've tried to research a solution to this, and it seems like I need to implement ajax in order to get the smart-select filters to work properly. I'm also sure my form.py is set up incorrectly, but I cannot figure out an alternate to to calling .objects.all() because I thought smart-selects would do the proper filtering in the background.

I will include both my models.py and forms.py in case the solution lies in them. I have never worked an ajax script before and my research hasn't pointed me in any direction where to start.

models.py

from django.db import models
from django.contrib.auth.models import User
from smart_selects.db_fields import ChainedForeignKey

class Status(models.Model):
    status = models.CharField(primary_key=True, max_length=25)

    ## For the API
    def __str__(self):
        return self.status

    ## Eliminates title plurality in the admin interface
    class Meta:
        verbose_name_plural="Status"

class Lab(models.Model):
    name = models.CharField(primary_key=True, max_length=100)

    ## For the API
    def __str__(self):
        return self.name

    ## Eliminates title plurality in the admin interface
    class Meta:
        verbose_name_plural="Lab"

class Category(models.Model):
    lab = models.ForeignKey(Lab)
    name = models.CharField(primary_key=True, max_length=100)

    ## For the API
    def __str__(self):
        return self.name

    ## Eliminates title plurality in the admin interface
    class Meta:
        verbose_name_plural="Category"


class SubCategory(models.Model):
    lab = models.ForeignKey(Lab)
    category = ChainedForeignKey(
            Category, 
            chained_field = 'lab', 
            chained_model_field = 'lab', 
            show_all = False, 
            auto_choose = True
        )
    subcategory = models.CharField(max_length=100)
    category = models.ForeignKey(Category)
    ## For the API
    #def __str__(self):
    #   return self.category

    ## Eliminates title plurality in the admin interface
    class Meta:
        verbose_name_plural="SubCategory"

forms.py

import datetime
from django import forms

## importing models
from .models import Category, Lab, SubCategory  ## need these tables to     populate dropdown menus 'Category' and 'Lab'
from submit_app.models import Incident
from smart_selects.db_fields import ChainedForeignKey

## importing crispy form utilities
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Field, Submit, Div
from crispy_forms.bootstrap import AppendedText, PrependedText, FormActions

## importing regex validator
from django.core.validators import RegexValidator

## Maybe best to try to use ModelForm....it seems to have overwhelming internet support
from django.forms import ModelForm


class IncidentForm(forms.ModelForm):

    class Meta:
        model = Incident
        fields = [  'date_occurred', 
                    'number_of_samples_affected',
                    'capa',
                    'title',
                    'description',
                    'category',
                    'lab',
                    'subcategory',
                    'upload1',
                    'upload2',
                    'upload3'
                    ]

    ## Pre-populated dropdown menu
    lab = forms.ModelChoiceField(
        queryset=Lab.objects.all(),
        label ="Lab"
    )

    ## Pre-populated dropdown menu
    category = forms.ModelChoiceField(
        queryset=Category.objects.all(),
        label = "Category"
    )

    subcategory = forms.ModelChoiceField(
        queryset=SubCategory.objects.all(),
        label = "SubCategory"
    )

    date_occurred = forms.DateField(
        label="Date Incident Occurred", 
        initial=datetime.date.today()
    )

    number_of_samples_affected = forms.IntegerField(
        label="Number of Samples Affected",
        initial='0'
    )

Solution

  • smart selects has it's own form field types. You are overriding that for category right now in your form:

    ## Pre-populated dropdown menu
    category = forms.ModelChoiceField(
        queryset=Category.objects.all(),
        label = "Category"
    )
    

    Remove all the code above from your form. When you are using a ChainedForeignKey, the model field's default form field type is provided by smart selects (see ChainedModelChoiceField in the source).

    The Javascript that performs AJAX calls is a small inline script that is rendered as part of the form field supplied by smart selects.

    You don't have to replace the code with anything, as the field is rendered automatically when included in a ModelForm.