Using two models in one FormWizard
I have two models configured in models.py
: Parent
andChild
class Parent(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField()
city = models.CharField()
class Child(models.Model):
id = models.AutoField(primary_key=True)
parent = models.ForeignKey(Parent)
name = models.CharField()
Now, while entering the form for this, I would like to do FormWizard
where the first form takes Parent
on and the second takes on details Child
, keeping the details of the previous form. Is it possible? And if so, please check me through some code samples.
source to share
Yes it is possible, and as you suggest, it is best to use Wizard Forms . You can customize your wizard shape using as many models as you like. I'll show you an example of how to create a form in 2 steps:
- The first step with a form to create a Parent object
- Second step for creating child object
I want to point out that in this case, perhaps you could consider doing a dynamic second step, in case the parent can have more than one child. I strongly recommended that you check both documentation pages:
- Django Wizard Form : This is useful for splitting large forms or combining different forms into one
- Django Formsets It's useful to have some kind of "dynamic" forms
First step: create as many forms as needed for the master form (forms.py)
- These forms you are about to create can be Normal Forms or ModelForms
-
Change "NameForm01" to the name you want for the form
class NameForm01 (forms.ModelForm): class Meta: model = Parent fields = ['name', 'city']
class NameForm02 (forms.ModelForm): class Meta: model = Child # We don't add the parent field because we relate the child # with the parent in the view fields = ['name' ]
Second step: create a master view (views.py)
from django.contrib.formtools.wizard.views import SessionWizardView
class YourNameWizard(SessionWizardView):
instance = None
form_list = [NameForm01, NameForm02]
template_name = "your_wizard_base.html" # Template used to render the forms
def done(self, form_list, **kwargs):
# Parent Information is in form 0
parent_name = form_list[0].cleaned_data['name']
parent_city = form_list[0].cleaned_data['city']
# Now we create the Parent object to relate with child
new_parent = Parent(name=parent_name, city=parent_city)
new_parent.save()
# Child information is in form 1
child_name = form_list[1].cleaned_data['name']
# Now we create the Child object related with new_parent
new_child = Child(name=child_name, parent=new_parent)
return HttpResponseRedirect(reverse('your_return_url'))
Third step: create url to manage wizard forms (urls.py)
from YOUR_PROJECT.forms import NameForm01, NameForm02
from YOUR_PROJECT.views.content import YourNameWizard
# ... other imports you have in your urls.py ...
urlpatterns = patterns('',
# ... other patterns ...
url(r'^your/url/?$', YourNameWizard.as_view([NameForm01, NameForm02]), name='your_url_name'),
# ... other patterns ...
)
Fourth step: create a template in which the wizard form will be created
This template is an example of a template that django offers in the documentation ( here )
Following this example, you should call this template "your_wizard_base.html" and place it in the Templates folder
{% extends "base.html" %}
{% load i18n %}
{% block head %}
{{ wizard.form.media }}
{% endblock %}
{% block content %}
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action="" method="post">{% csrf_token %}
<table>
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form }}
{% endfor %}
{% else %}
{{ wizard.form }}
{% endif %}
</table>
{% if wizard.steps.prev %}
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.first }}">{% trans "first step" %}</button>
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">{% trans "prev step" %}</button>
{% endif %}
<input type="submit" value="{% trans "submit" %}"/>
</form>
{% endblock %}
This sample template may be enough for you to practice with the WizardForm and then adapt it to your wishes.
source to share