'django 3.2 inline_formset with related models many to one
I'd like to make my form look like this

but my following this approach my output looks like this

Here are my models
class Question(models.Model):
id = models.BigAutoField(primary_key=True)
question = models.CharField(max_length=255, unique=True)
is_active = models.BooleanField(default=False)
class Declaration(models.Model):
id = models.BigAutoField(primary_key=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='declarations', on_delete=models.CASCADE)
created_at = models.DateTimeField(verbose_name='created', auto_now_add=True)
class Checklist(models.Model):
id = models.BigAutoField(primary_key=True)
declaration = models.ForeignKey(Declaration, related_name='checklist_declarations', on_delete=models.CASCADE)
question = models.ForeignKey(Question, related_name='checklist_questions', on_delete=models.CASCADE, limit_choices_to={'is_active': 'True'})
is_yes = models.BooleanField()
forms
class ChecklistInlineFormSet(BaseInlineFormSet):
def clean(self):
if any(self.errors):
#Don't bother validating the formset unless each form is valid on its own
return
questions = []
for form in self.forms:
question = form.cleaned_data.get('question')
if question in questions:
raise ValidationError(_('Question must be distinct'), code='invalid')
questions.append(question)
class HorizontalRadionRenderer(forms.RadioSelect):
def render(self):
return mark_safe(u'\n'.join([u'%s\n' % w for w in self]))
class ChecklistForm(forms.ModelForm):
ANSWER_CHOICES = [
(True, 'Yes'),
(False, 'No')
]
is_yes = forms.TypedChoiceField(
choices=ANSWER_CHOICES,
coerce=lambda x: x == 'True',
widget=forms.RadioSelect,
required=True
)
class Meta:
model = Checklist
fields = ['question', 'is_yes']
views
declaration.views
def checklist(request):
FS_PREFIX = 'question_fs'
user = request.user
result = ""
if request.method == 'POST':
# Use your custom FormSet class as an argument to inlineformset_factory
formset = inlineformset_factory(Declaration, Checklist, form=ChecklistForm, fk_name='declaration', formset=ChecklistInlineFormSet)
declaration = Declaration()
declaration.user = user
checklist = formset(request.POST, prefix=FS_PREFIX, instance=declaration)
char = request.POST
print(char)
if checklist.is_valid():
with transaction.atomic():
declaration.save()
checklist.declaration = declaration
checklist.save()
result = 'true'
#Updates profile's health status based on declaration submitted
declaration.health_status()
return result
else:
print(checklist.errors)
print(checklist.non_form_errors())
print('checklist form invalid')
messages.add_message(request, messages.ERROR, 'Checklist invalid! Make sure to answer the questions legitimately.')
questions = []
questions = [{'question': str(q.id),'is_yes': None} for q in Question.objects.all().order_by('ordering')]
formset = inlineformset_factory(Declaration, Checklist, form=ChecklistForm, fk_name="declaration", extra=len(questions),can_delete=False)
question_formset = formset(prefix=FS_PREFIX, initial=questions)
question_only = Question.objects.all().order_by('ordering')
context = {
'question_formset': question_formset,
'question_only': question_only
}
result = context
return result
student.views
from declaration.views import checklist
def create_declaration(request):
the_checklist = checklist(request)
if the_checklist == 'true':
print(the_checklist)
return redirect('student:index')
else:
print(the_checklist)
return render(request, 'student/declaration/declaration-form.html', the_checklist)
template
<div class="row m-0 p-0 mb-2">
<div class="col-lg-12">
<div class="pb-2">
{{ question_formset.management_form|crispy }}
{% crispy question_formset %}
</div>
</div>
</div>
If you can make the select dropdown menu into text or label would be great.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
