Home > Back-end >  Model.Form Queryset
Model.Form Queryset

Time:03-21

I have a model.form which I need to apply a queryset to filter the choices available within a select field.

class AnswerForm(ModelForm):
    class Meta:
        model = ProjectQuestionnaireAnswer
        fields = ('answer','notes')

        widgets = {
            'answer': forms.Select(choices = Choice.objects.filter(question_id = 1),attrs={'class': 'form-control select2'}),
            'notes': forms.Textarea(attrs={'class': 'form-control','placeholder': 'Add notes to question here'}),
        }
class Choice(models.Model):
    question = models.ForeignKey(ProjectQuestionnaireQuestion, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)

    def __str__(self):
        return str(self.choice_text)
class ProjectQuestionnaireAnswer(models.Model):
    YN_Choices = [
        ('Yes', 'Yes'),
        ('No', 'No'),
        ('Unknown', 'Unknown')
    ]
    question = models.ForeignKey(ProjectQuestionnaireQuestion, on_delete=models.CASCADE)
    answer = models.ForeignKey(Choice, on_delete=models.CASCADE,null=True)
    notes = models.TextField(blank=True)
    response = models.ForeignKey(ProjectQuestionnaireResponse, on_delete=models.CASCADE)
    
    class Meta:
        constraints = [
                models.UniqueConstraint(fields=['question','response'], name='project_unique_response2'),
            ]

    def __str__(self):
        return str(self.answer)
def get_questionnaire(request, project_id, questionnaire_id):

    # Get or Create the Response object for the parameters
    next = request.POST.get('next', '/')
    response, created = ProjectQuestionnaireResponse.objects.get_or_create(
        project_name_id=project_id, questionnaire_id=questionnaire_id
    )

    AnswerFormSet = modelformset_factory(ProjectQuestionnaireAnswer, form=AnswerForm, fields=('answer','notes',), extra=0)

    answer_queryset = ProjectQuestionnaireAnswer.objects.filter(response=response
    ).order_by('question__sequence'
    ).select_related('question')

    if request.method == 'POST':
        formset = AnswerFormSet(request.POST)
        instances = formset.save()
        return HttpResponseRedirect(next)
    else:
        # Get the list of questions for which no Answer exists
        new_answers = ProjectQuestionnaireQuestion.objects.filter(
            questionnaire__projectquestionnaireresponse=response
        ).exclude(
            projectquestionnaireanswer__response=response
        )

        # This is safe to execute every time. If all answers exist, nothing happens
        for new_answer in new_answers:
            ProjectQuestionnaireAnswer(question=new_answer, response=response).save()

        answer_formset = AnswerFormSet(queryset=answer_queryset)
                

    return render(request, 'project_evaluation.html', {'formset': answer_formset,'project_name':response.project_name,'title':response.questionnaire.title})

I'm not sure how to write the query to only return the choices related to the question. I've tested with choices = Choice.objects.filter(question_id = 1) which does return me the choices for question 1, but need it for each question?

And then how do I present this in my template?

{{ form.answer.choices }} ??

Thanks

CodePudding user response:

You need to implement it in the __init__ method.

This is my suggestion:

class AnswerForm(ModelForm):
    class Meta:
        model = ProjectQuestionnaireAnswer
        fields = ('answer','notes')

        widgets = {
            'notes': forms.Textarea(attrs={'class': 'form-control','placeholder': 'Add notes to question here'}),
        }

    def __init__(self, *args, **kwargs):
         question_id = kwargs.pop('question_id')
         super().__init__(*args, **kwargs)
         self.fields['answer'] = forms.ModelChoiceField(
             queryset=Choice.objects.filter(question_id=question_id),
             widget=forms.Select(attrs={'class': 'form-control select2'})
         )

Then when initializing the form, you need to pass to it the question_id argument. For the example in the post: AnswerForm(question_id=1)

Let me know if that works.

  • Related