You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django 3.2 外键字段循环渲染、表单问题文本展示及数据保存异常技术问询

Let's tackle your Django form issues step by step, with practical code adjustments and explanations:


1. Rendering Dynamic Fields for Each Question

To loop through active Question instances and render a checkbox for each, you'll need to use a formset—this lets you generate multiple form fields tied to your Checklist model, one per question.

First, Update Your Models

Your Question model is missing the is_active field referenced in Checklist's limit_choices_to, so add that:

# models.py
class Question(models.Model):
    id = models.BigAutoField(primary_key=True)
    title = models.CharField(max_length=50, unique=True)
    question = models.CharField(max_length=255, unique=True)
    is_active = models.BooleanField(default=True)  # Add this line

Adjust Your Forms

Modify ChecklistForm to hide the question dropdown and use the question text as the checkbox label. Then create a formset for multiple checklist entries:

# forms.py
from django import forms
from django.forms import modelformset_factory
from declaration.models import Checklist, Question, Declaration

class DeclarationForm(forms.ModelForm):
    class Meta:
        model = Declaration
        exclude = ['user']  # We'll set the user programmatically in the view

class ChecklistForm(forms.ModelForm):
    is_yes = forms.BooleanField(required=False)

    class Meta:
        model = Checklist
        fields = ['question', 'is_yes']
        widgets = {
            'question': forms.HiddenInput(),  # Hide the question dropdown
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Set checkbox label to the question text if initial data exists
        if 'question' in self.initial:
            question = Question.objects.get(id=self.initial['question'])
            self.fields['is_yes'].label = question.question

# Create a formset for Checklist (one form per active question)
ChecklistFormSet = modelformset_factory(Checklist, form=ChecklistForm, extra=0)

2. Fixing Checklist Saving Issues

Your original view only handled a single Checklist form, which can't process multiple question entries. Here's how to update the view to handle the formset:

# views.py
from django.shortcuts import render, redirect
from .forms import DeclarationForm, ChecklistFormSet
from .models import Question

def submit(request):
    active_questions = Question.objects.filter(is_active=True)
    
    if request.method == 'POST':
        declaration_form = DeclarationForm(request.POST)
        checklist_formset = ChecklistFormSet(request.POST, queryset=Checklist.objects.none())
        
        if declaration_form.is_valid() and checklist_formset.is_valid():
            # Save declaration with current user
            declaration = declaration_form.save(commit=False)
            declaration.user = request.user
            declaration.save()
            
            # Save each checklist entry linked to the new declaration
            for form in checklist_formset:
                checklist = form.save(commit=False)
                checklist.declaration = declaration
                checklist.save()
            
            return redirect('student-dashboard')
    else:
        # Initialize formset with one empty form per active question
        checklist_formset = ChecklistFormSet(queryset=Checklist.objects.none())
        # Set initial question data and labels for each form
        for form, question in zip(checklist_formset, active_questions):
            form.initial['question'] = question.id
            form.fields['is_yes'].label = question.question
        
        declaration_form = DeclarationForm()
    
    return render(request, 'declaration/submit.html', {
        'declaration_form': declaration_form,
        'checklist_formset': checklist_formset,
    })

3. Displaying Question Text Instead of Dropdowns

The template will loop through the formset and render each checkbox with the question text as its label. Here's a sample template:

<!-- submit.html -->
<form method="post">
    {% csrf_token %}
    
    <!-- Declaration form (omit if you don't have other fields besides user) -->
    {{ declaration_form.as_p }}
    
    <!-- Formset management data (required for Django to handle the formset) -->
    {{ checklist_formset.management_form }}
    
    <!-- Render each question's checkbox -->
    {% for form in checklist_formset %}
        {{ form.as_p }}
    {% endfor %}
    
    <button type="submit">Submit Declaration</button>
</form>

Key Explanations:

  • Formsets: The ChecklistFormSet creates one form per active Question, letting you handle multiple checklist entries in one submission.
  • Hidden Question Field: We hide the question field (using HiddenInput) so users can't modify it, but still pass the question ID to the backend.
  • Saving Checklist Entries: We loop through each valid form in the formset, link it to the new Declaration, and save each entry individually.

内容的提问来源于stack exchange,提问作者tenzai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 15:24:08