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

Django动态表单生成器:删除问题后自动重排编号方案咨询

Fixing Dynamic Question Number Reordering in Django FormView Builder

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.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 20:22:57