Long time programmer, newer to Django with only a couple lightweight crud and api projects complete. I’m building a survey builder application, and chat-gpt has me knee deep in formsets. Questions are added with a modal that is initiated with a JS call (button pressed). When adding a question, forms are populated by JS, and retrieving the formeset in the view works beautifully. On edit, I need to retrieve the question model and its options (multiple choice) and render the form (and formset). Everything works except I get an empty formset. I don’t know how much code helpers want to see, so I’ll paste in models, forms, form template and the view that’s causing errors. Any pointers in the right direction appreciated.
survey_section_component = models.ForeignKey(SurveySectionComponent, on_delete=models.CASCADE,
related_name='surveyquestion_set')
question_text = models.TextField()
question_type = models.CharField(max_length=20, choices=[
('multiple_choice', 'Multiple Choice'),
('short_answer', 'Short Answer'),
('paragraph', 'Paragraph'),
('dropdown', 'Drop Down'),
('checkbox', 'Checkbox'),
('rating_scale', 'Rating Scale'),
])
order = models.IntegerField()
def __str__(self):
return self.question_text
# This method can be used to retrieve the options related to this question
def get_options(self):
return self.options.all()
class SurveyQuestionOption(models.Model):
survey_question = models.ForeignKey(SurveyQuestion, on_delete=models.CASCADE, related_name='options')
option_text = models.CharField(max_length=255)
order = models.IntegerField() # Useful if you want to allow ordering of options
def __str__(self):
return self.option_text
class SurveyQuestionForm(forms.ModelForm):
class Meta:
model = SurveyQuestion
fields = ['question_text', 'question_type']
def __init__(self, *args, **kwargs):
super(SurveyQuestionForm, self).__init__(*args, **kwargs)
self.fields['question_text'].widget.attrs.update({'class': 'form-control'})
self.fields['question_type'].widget.attrs.update({'class': 'form-control'})
class SurveyQuestionOptionForm(forms.ModelForm):
class Meta:
model = SurveyQuestionOption
fields = ['option_text', 'order']
def __init__(self, *args, **kwargs):
super(SurveyQuestionOptionForm, self).__init__(*args, **kwargs)
self.fields['option_text'].widget.attrs.update({'class': 'form-control'})
self.fields['order'].widget.attrs.update({'class': 'form-control', 'type': 'number'})
SurveyQuestionOptionFormSet = inlineformset_factory(
SurveyQuestion,
SurveyQuestionOption,
form=SurveyQuestionOptionForm,
extra=0 # No extra forms initially
)
def edit_question_component(request, component_id):
component = get_object_or_404(SurveySectionComponent, id=component_id)
question = get_object_or_404(SurveyQuestion, survey_section_component=component)
if request.method == 'POST':
question_form = SurveyQuestionForm(request.POST, instance=question)
option_formset = SurveyQuestionOptionFormSet(request.POST, instance=question)
if question_form.is_valid() and option_formset.is_valid():
question_form.save()
option_formset.save()
return JsonResponse({'success': True, 'component_id': component.id, 'content': question.question_text})
else:
return JsonResponse({'success': False, 'errors': question_form.errors})
# Get request, grab the options and build the edit
question_form = SurveyQuestionForm(instance=question)
options = question.options.all()
print(f"Options for question {question.id}:")
for option in options:
print(f"Option Text: {option.option_text}, Order: {option.order}")
option_formset = SurveyQuestionOptionFormSet(queryset=question.options.all())
print(f"Option FormSet forms: {[form.cleaned_data for form in option_formset]}")
for form in option_formset:
print(form.initial) # This should show the initial data being loaded into the formset
print(f"Option FormSet {option_formset}")
form_html = render_to_string('surveys/partials/question_component_form.html', {
'question_form': question_form,
'option_formset': option_formset,
'component_id': component_id,
'button_text': 'Save Changes',
}, request=request)
return JsonResponse({'success': True, 'form_html': form_html})
Output from debugging prints
Options for question 15:
Option Text: Red, Order: 1
Option Text: Blue, Order: 2
Option FormSet forms:
Option FormSet