djangodjango-modelsdjango-formsmodelchoicefield

Select a valid choice. That choice is not one of the available choices


In my app, i have a dropdown (department) that's depending on the previously selected value from a dropdown(faculty field). I am using ajax to get the new value which works fine. However, when i try saving the form, i get Select a valid choice. That choice is not one of the available choices.

Here is my model

from django.db import models
from system.models import FacultyData, DepartmentData, SessionData, SemesterData, SettingsData

# Create your models here.

class SchoolFees(models.Model):
    fid = models.ForeignKey(FacultyData, on_delete= models.SET_NULL, null=True)
    did = models.ForeignKey(DepartmentData, on_delete= models.SET_NULL, null=True)
    sid = models.ForeignKey(SessionData, on_delete= models.SET_NULL, null=True)
    amount = models.CharField(max_length=30)

    def __str__(self):
        return self.amount

and my form.py

from django import forms
from . import models
from system.models import FacultyData, DepartmentData, SessionData
from .models import SchoolFees



class FeesCreationForm(forms.ModelForm):
    fid = forms.ModelChoiceField(queryset=FacultyData.objects.all(), empty_label="--Select Faculty--",
                                 widget=forms.Select(attrs={'class': 'form-control'}))

    did = forms.ModelChoiceField(queryset=DepartmentData.objects.all(), empty_label="--Select Faculty First--",
                                 widget=forms.Select(attrs={'class': 'form-control'}))

    sid = forms.ModelChoiceField(queryset=SessionData.objects.all(), empty_label="--Select Session--",
                                 widget=forms.Select(attrs={'class': 'form-control'}))

    class Meta:
        model = models.SchoolFees
        fields = ['sid', 'fid', 'did', 'amount']

        widgets = {
            'amount': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter Amount'})

        }



  def __init__(self, *args, **kwargs):
    super(FeesCreationForm, self).__init__(*args, **kwargs)
    self.fields['did'].queryset = DepartmentData.objects.none()

   # Get did queryset for the selected fid
    if 'fid' in self.data:
        try:
            fd = int(self.data.get('fid'))
            self.fields['did'].queryset = DepartmentData.objects.filter(fid=fd).order_by('dept_name')
        except (ValueError, TypeError):
            pass # invalid input from the client; ignore and use empty queryset

in my view.py, i have a method for getting department based on the faculty chosen. and also for saving the new fee

def create_fee(request):
    app = settings.CONFIG
    #table = FacultyTable(FacultyData.objects.all())
   # RequestConfig(request, paginate={'per_page': 10}).configure(table)
    context = {"form": FeesCreationForm,  'app': app}
    return render(request, 'bursary.html', context)

def get_department(request):

    fid = request.GET.get('fid', None)

    datas = {
        'is_taken': DepartmentData.objects.filter(fid=fid)
    }
    department = list(DepartmentData.objects.filter(fid=fid).values())
    data = dict()
    data['department'] = department
    return JsonResponse(data)

def save_fee(request):
    app = settings.CONFIG
    # table = FacultyTable(FacultyData.objects.all())
    # RequestConfig(request, paginate={'per_page': 10}).configure(table)
    form = FeesCreationForm(request.POST)
    context = {"form": FeesCreationForm, 'app': app}
    if form.is_valid():
        form.save()
        messages.add_message(request, messages.SUCCESS, "Fees added successfully")
    else:
        messages.add_message(request, messages.ERROR, form.errors)

    return redirect('bursary:create_fee')

i don't know where i am getting this wrong or how to fix it


Solution

  • This is because you initialize your queryset empty (which is fine), but never update it within the form object itself. So the server side validation is failing.

    Try updating your queryset in the __init__ method of your FeesCreationForm:

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Init empty did queryset
        self.fields['did'].queryset = DepartmentData.objects.none()
    
        # Get did queryset for the selected fid
        if 'fid' in self.data:
            try:
                fid = int(self.data.get('fid'))
                self.fields['did'].queryset = DepartmentData.objects.filter(
                    fid=fid).order_by()
            except (ValueError, TypeError):
                # invalid input from the client; ignore and use empty queryset
                pass