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.