使用FormWizard创建Django多步骤ModelForm遇问题求助
Hey there! Let's dig into your Django multi-step ModelForm issue with FormWizard. Since you mentioned you're not getting the expected results and ran into errors, let's break down common pitfalls and actionable fixes using the components you referenced (urls.py, models.py, views.py).
Your core models (Patient, Symptom, Disease) and intermediate Consultation model need to be properly configured to play nice with FormWizard. Here’s a corrected example that aligns with your description:
# models.py from django.db import models class Patient(models.Model): name = models.CharField(max_length=100) age = models.IntegerField() email = models.EmailField(blank=True) # Add any other patient-specific fields class Symptom(models.Model): name = models.CharField(max_length=100) description = models.TextField(blank=True) class Disease(models.Model): name = models.CharField(max_length=100) linked_symptoms = models.ManyToManyField(Symptom, related_name='associated_diseases') # Intermediate Consultation model linking Patient to Disease/Symptoms class Consultation(models.Model): patient = models.ForeignKey(Patient, on_delete=models.CASCADE, related_name='consultations') diagnosed_disease = models.ForeignKey(Disease, on_delete=models.CASCADE) reported_symptoms = models.ManyToManyField(Symptom) consultation_date = models.DateTimeField(auto_now_add=True) doctor_notes = models.TextField(blank=True)
Key check: Ensure foreign keys/many-to-many fields have clear related_name values to avoid reverse lookup conflicts.
Note: Django’s built-in FormWizard was moved to the django-formtools package, so first make sure you’ve installed it with pip install django-formtools and added formtools to your INSTALLED_APPS in settings.py.
Here’s a properly structured multi-step view using SessionWizardView:
# views.py from django.shortcuts import redirect from formtools.wizard.views import SessionWizardView from .models import Patient, Consultation from .forms import PatientForm, SymptomSelectionForm, ConsultationFinalForm class PatientConsultationWizard(SessionWizardView): template_name = 'wizard_step.html' # Define the sequence of forms for each step form_list = [ ('patient_info', PatientForm), ('select_symptoms', SymptomSelectionForm), ('finalize_consultation', ConsultationFinalForm), ] def done(self, form_list, **kwargs): # Process data from each step in order # Step 1: Save patient patient_form = form_list[0] patient = patient_form.save() # Step 2: Grab selected symptoms symptom_form = form_list[1] selected_symptoms = symptom_form.cleaned_data['selected_symptoms'] # Step 3: Save consultation and link related data consultation_form = form_list[2] consultation = consultation_form.save(commit=False) consultation.patient = patient consultation.save() # Add many-to-many symptoms after saving the consultation instance consultation.reported_symptoms.add(*selected_symptoms) # Redirect to the patient's detail page on completion return redirect('patient_detail', pk=patient.pk) # Example form definitions (create these in forms.py) # forms.py from django import forms from .models import Patient, Symptom, Disease, Consultation class PatientForm(forms.ModelForm): class Meta: model = Patient fields = ['name', 'age', 'email'] class SymptomSelectionForm(forms.Form): selected_symptoms = forms.ModelMultipleChoiceField( queryset=Symptom.objects.all(), widget=forms.CheckboxSelectMultiple, label="Select reported symptoms" ) class ConsultationFinalForm(forms.ModelForm): class Meta: model = Consultation fields = ['diagnosed_disease', 'doctor_notes']
Ensure your urls.py maps the wizard view correctly, alongside your other patient views:
# urls.py from django.urls import path from .views import PatientListView, PatientDetailView, PatientConsultationWizard urlpatterns = [ path('patients/', PatientListView.as_view(), name='patient_list'), path('patients/<int:pk>/', PatientDetailView.as_view(), name='patient_detail'), path('patients/new-consultation/', PatientConsultationWizard.as_view(), name='patient_consultation_wizard'), ]
Create a template (wizard_step.html) to render each step’s form and navigation controls:
{% extends 'base.html' %} {% block content %} <h3>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</h3> <form method="post"> {% csrf_token %} {{ wizard.management_form }} {% if wizard.form.forms %} <!-- Handle formsets if needed --> {{ wizard.form.management_form }} {% for form in wizard.form.forms %} {{ form.as_p }} {% endfor %} {% else %} <!-- Render single form for the step --> {{ wizard.form.as_p }} {% endif %} <div class="wizard-controls"> {% if wizard.steps.prev %} <button type="submit" name="wizard_goto_step" value="{{ wizard.steps.prev }}">Previous</button> {% endif %} <button type="submit"> {% if wizard.steps.last %}Finish{% else %}Next Step{% endif %} </button> </div> </form> {% endblock %}
- "FormWizard not found": Double-check
django-formtoolsis installed and added toINSTALLED_APPS. - "Cannot assign None to 'patient'": You forgot to save the Patient instance before linking it to Consultation. Always save parent models first, then use
commit=Falsefor related models to add associations post-save. - Data not saving to consultation: Verify you’re accessing
cleaned_datacorrectly for each form, and that you’re adding many-to-many fields (like symptoms) after saving the Consultation instance. - Steps not advancing: Ensure
wizard.management_formis included in your template—it handles step tracking.
内容的提问来源于stack exchange,提问作者raphael iivii

