djangodjango-viewsdjango-formsdjango-class-based-viewsdjango-request

How to pass self.request data in django form?


I want to pass self.request data in the form class. I can access it in View, but unable to access it in form class.

class AttendanceCreateView(LoginRequiredMixin, CreateView):
    model = Attendance
    template_name = 'attendance/attendances_new.html'
    form_class = AttendanceForm

    def get_initial(self):
        initial = super().get_initial()
        initial['class_name'] = self.request.GET.get('class', '')
        return initial

My Form class:

class AttendanceForm(forms.ModelForm):
    class_name = forms.ChoiceField(choices=CLASS_NAMES, disabled=True)
    teacher = forms.ModelMultipleChoiceField(
        queryset=Teacher.objects.all().order_by('id'))
    subject_name = forms.ChoiceField(choices=[])
    total_students = forms.IntegerField(initial=0)
    unique_code = forms.IntegerField(initial=0)

    class Meta:
        model = Attendance
        fields = ['class_name', 'teacher', 'subject_name',
                  'total_students', 'unique_code']

    def __init__(self, *args, **kwargs):
        super(AttendanceForm, self).__init__(*args, **kwargs)
        
        # This I need to be done
        # if self.request.GET.get('class', '') = 'class1':
        #    self.fields['subject_name'].choices = MY_CHOICES_1 
        # elif self.request.GET.get('class', '') = 'class2':
        #    self.fields['subject_name'].choices = MY_CHOICES_2
        

I want to set subject_name choices according to the request values passed. For class 1, I want different subject choices., and for class 2, different subject choices etc. So getting request data is important.

Is there any way to set the initial choice in direct View like I did for class_name? Or any suggestions on how to do it in form?


Solution

  • Pass the request through the form_kwargs:

    class AttendanceCreateView(LoginRequiredMixin, CreateView):
        model = Attendance
        template_name = 'attendance/attendances_new.html'
        form_class = AttendanceForm
    
        def get_form_kwargs(self):
            kwargs = super().get_form_kwargs()
            kwargs['request'] = self.request
            return kwargs
    
        def get_initial(self):
            initial = super().get_initial()
            initial['class_name'] = self.request.GET.get('class', '')
            return initial

    and then we handle this in the form:

    class AttendanceForm(forms.ModelForm):
        # …
    
        def __init__(self, *args, request, **kwargs):
            self.request = request
            super().__init__(*args, **kwargs)
            if self.request.GET.get('class', '') == 'class1':
                self.fields['subject_name'].choices = MY_CHOICES_1
            elif self.request.GET.get('class', '') == 'class2':
                self.fields['subject_name'].choices = MY_CHOICES_2

    Note: Since PEP-3135 [pep], you don't need to call super(…) with parameters if the first parameter is the class in which you define the method, and the second is the first parameter (usually self) of the function.