Django动态表单生成器:删除问题后自动重排编号方案咨询
I’ve tackled a similar problem with dynamic Django forms where deleting UI elements broke sequential numbering—critical for mapping form data to model fields. Here are two solid solutions depending on whether you want to stick with your current setup or leverage Django’s built-in tools:
Solution 1: Frontend Reordering Logic (For Custom Form Builders)
If you want to keep your existing FormView setup, you’ll need JavaScript to reindex all question elements right after a deletion. This updates the number text, CSS classes, and form field name attributes to maintain continuous numbering.
Example JavaScript Implementation
// Attach delete event listeners to all question delete buttons document.querySelectorAll('.delete-question-btn').forEach(btn => { btn.addEventListener('click', function(e) { e.preventDefault(); // Remove the parent question container const questionContainer = this.closest('.question-container'); if (questionContainer) { questionContainer.remove(); // Trigger reordering after deletion reorderQuestions(); } }); }); function reorderQuestions() { const allQuestionContainers = document.querySelectorAll('.question-container'); allQuestionContainers.forEach((container, index) => { const newNumber = index + 1; // Start numbering from 1 // Update visible question number text (e.g., "问题 1" → "问题 2") const numberDisplay = container.querySelector('.question-number'); if (numberDisplay) { numberDisplay.textContent = `问题 ${newNumber}`; } // Update container class names (e.g., question-1 → question-2) container.classList.forEach(className => { if (className.startsWith('question-')) { container.classList.remove(className); } }); container.classList.add(`question-${newNumber}`); // Update form field names (e.g., name="question_1" → name="question_2") const formFields = container.querySelectorAll('input, textarea, select'); formFields.forEach(field => { // Adjust the regex to match your field name pattern const nameRegex = /^(question|answer)_\d+/; if (field.name.match(nameRegex)) { field.name = field.name.replace(nameRegex, `$1_${newNumber}`); } }); }); }
Key Notes:
- Adjust selectors (
.question-container,.question-number) and regex patterns to match your actual HTML structure. - Test edge cases: deleting the first/last question, deleting multiple questions in sequence.
Solution 2: Use Django FormSets (Recommended)
If you’re open to refactoring, Django’s FormSet is built specifically for dynamic forms with add/remove functionality. It handles automatic indexing, validation, and data mapping out of the box—no manual numbering needed.
Backend Setup
# forms.py from django import forms from django.forms import formset_factory class QuestionForm(forms.Form): question_text = forms.CharField(label='问题', widget=forms.TextInput(attrs={'class': 'question-input'})) answer = forms.CharField(label='答案', widget=forms.Textarea(attrs={'rows': 3})) # Create a formset with 1 initial form, allow deletion QuestionFormSet = formset_factory(QuestionForm, extra=1, can_delete=True) # views.py from django.views.generic.edit import FormView from .forms import QuestionFormSet class DynamicQuestionView(FormView): template_name = 'dynamic_form.html' form_class = QuestionFormSet success_url = '/form-submitted/' def form_valid(self, formset): # Process valid form data for form in formset: if form.cleaned_data and not form.cleaned_data.get('DELETE'): # Map to your model fields # Example: QuestionModel.objects.create(text=form.cleaned_data['question_text'], ...) pass return super().form_valid(formset)
Frontend for FormSets
Django generates form fields with structured names like form-0-question_text, form-1-question_text. To handle deletions and reordering, add simple logic to update form indices:
// Example reordering for FormSets function reorderFormset(formsetPrefix) { const formContainers = document.querySelectorAll(`.formset-${formsetPrefix}`); formContainers.forEach((container, index) => { // Update form index in field names const fields = container.querySelectorAll('input, textarea, select'); fields.forEach(field => { const nameRegex = new RegExp(`^${formsetPrefix}-\\d+-`); field.name = field.name.replace(nameRegex, `${formsetPrefix}-${index}-`); field.id = field.id.replace(nameRegex, `${formsetPrefix}-${index}-`); }); // Update deletion checkbox name/id const deleteCheckbox = container.querySelector(`input[name$="-DELETE"]`); if (deleteCheckbox) { deleteCheckbox.name = `${formsetPrefix}-${index}-DELETE`; deleteCheckbox.id = `${formsetPrefix}-${index}-DELETE`; } }); }
Why This Is Better:
- FormSets handle validation for missing/duplicate indices automatically.
- No need to maintain custom numbering logic—Django manages the form structure.
- Easier to scale (add more fields, adjust validation rules) without rewriting numbering code.
内容的提问来源于stack exchange,提问作者Vishesh Mangla

