The problem is how to populate each form of a Model Formset using a queryset, and also providing initial data to the unbound forms in the formset. Why? I have a model called Answer. I want to create many Answers to a Question model, and each Question is within a Section, another model. When in the question detail page, I already know the Section and the Question the Answer object should belong to, and these will eventually just be rendered as hidden fields, but I need them in order to save the Answer object.
My models (reduced to the essential fields):
class Section(models.Model):
section = models.CharField(max_length=100)
def __str__(self):
return self.section
class Question(models.Model):
question = models.CharField(max_length=500)
section = models.ForeignKey(Section, on_delete=models.CASCADE)
def __str__(self):
return self.question
class Answer(models.Model):
answer = models.CharField(max_length=200, null=True, default='')
question = models.ForeignKey(Question, on_delete=models.CASCADE)
section = models.ForeignKey(Section, on_delete=models.CASCADE)
def __str__(self):
return self.answer
My form:
class AddAnswerForm(forms.ModelForm):
class Meta:
model = Answer
fields = ['answer', 'question', 'section']
I want to do this with Model Formsets since the user should be able to keep adding answers, and also edit answers previously given. I've looked at the docs, which for django are excellent, and found how to add initial data here. Initially, the template was displaying ALL Answer objects, which I saw is done by default, until I see this on how to use a queryset to limit the results. Then tried to use
initial={'section': section, 'question': question}
Which created a KeyError
So how do I provide default values to section
and question
to each answer in the formset, while at the same time populate the bound formset forms with previously saved Answer objects?
The answer, which is in the docs and on stackoverflow, with quite a bit of searching and trying things out turns out to be quite simple. For me, it ended up being putting initial in [ ]!
views.py
AnswerFormSet = modelformset_factory(Answer, form=AddAnswerForm)
formset = AnswerFormSet(request.POST or None,
initial=[{'section': section, 'question': question}],
queryset=Answer.objects.filter(question=question))
if formset.is_valid():
formset.save()
return redirect('question', question.pk, question.question)
Now it works fine, but if the question was a duplicate, or if there is a better method, I would appreciate the feedback. After struggling for hours, I thought it would be useful for others in a similar situation.
EDIT
I was so consumed with model formsets, that I did not read the docs on what they are based on, formsets! All the relevant information is there. Moral of the story. Read the docs!