I am trying to perform the following using Django :
Wizard containing two formds
First form is a simple form containing some Ajax to compute automatically some fields
Second form is a user registration
The problem is the following :
The first form is displayed correctly and the Ajax within the page is working fine
The second form is never displayed after pushing on the button "submit"
The code is as follows :
urls.py
from forms import InsertPropertyForm1, InsertPropertyForm2
from views import InsertPropertyWizard
urlpatterns = patterns('',
url(r'^addProperty/$', InsertPropertyWizard.as_view([InsertPropertyForm1, InsertPropertyForm2]), name='addProperty'),
)
views.py
FORMS = [("property", InsertPropertyForm1),
("test", InsertPropertyForm2)
]
TEMPLATES = {'0': 'realEstate/addProperty.html',
'1' : 'realEstate/test.html',
}
class InsertPropertyWizard(SessionWizardView):
def get_template_names(self):
print ("next step !!!!! " + str(self.steps.current))
return [TEMPLATES[self.steps.current]]
def done(self, form_list, **kwargs):
print "Wizard done"
#do_something_with_the_form_data(form_list)
return HttpResponseRedirect('http://TO_FILL_IN')
realEstate/addProperty.html
{% extends 'realEstate/base.html' %}
{% load socialaccount %}
{% load i18n %}
{% block head %}
{{ wizard.form.media }}
{% endblock %}
{% block content %}
<h1> Insert an ad </h1>
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form class="form-horizontal" role="form" action="" method="post">{% csrf_token %}
<table>
{{ wizard.management_form }}
</table>
{{ form.non_field_errors }}
<fieldset>
<legend>Localisation</legend>
<div class="form-group">
{{ form.country.errors }}
<label class="col-lg-1" for="id_country">{{form.country.label}}</label>
<div class="col-lg-1">
{{ form.country }}
</div>
</div>
</fieldset>
</fieldset>
{% 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 %}
Just thought it could help someone.
Problem was that one of the field was not defined in the form and I forgot to include it in the template.
The behaviour of the wizard was correct. It got stuc on the first page but did not display the error on the screen as the field was not displayed.
Got me crazy but it was my fault.
Cheers
Related
I want to save the created objects, but I can't get it to work. I can successfully fill out the form and submit it, but no data is saved in the database. Any suggestions as to what I'm doing incorrectly? I tried using form_data[0].save but it threw 'dict' object has no attribute 'save'
views
from django.shortcuts import render
from formtools.wizard.views import SessionWizardView
from django.core.files.storage import FileSystemStorage
from .forms import (
WithdrawForm1,
WithdrawForm2,
)
from django.conf import settings
import os
class WithdrawWizard(SessionWizardView):
template_name = 'withdraw.html'
form_list = [WithdrawForm1, WithdrawForm2]
file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'media_root'))
def done(self, form_list, **kwargs):
form_data = [form.cleaned_data for form in form_list]
return render(self.request, 'done.html', {'data': form_data})
Template
{% load i18n %}
{% block head %}
{{ wizard.form.media }}
{% endblock %}
{% block content %}
<div class="row d-flex justify-content-center" style="height: 50vh;">
<div class="col-md-6">
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action="" method="post" enctype=multipart/form-data>{% 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>
</div>
</div>
{% endblock %}
form_data is a list of dictionaries of form.cleaned_data. You need to save the form instances, not the cleaned data dictionaries.
Try this:
for form in form_list:
form.save()
I am trying to build website using Flask, and can't find solution to one problem. I am trying to hide or show input field, based on RadioFeild choice. Also, if input field showing, it have to be required. I actually have everything working, besides knowing what RadioField choice was selected. I can see the form when loading page on 127.0.0.1:5000 and I can see RadioField with 2 choices: Yes and No, but when I click on yes, there are no changes, hidden input field is still not showing. Please, help!
app.py
class MyClass(FlaskForm):
my_field = RadioField("bla-bla-bla", choices=[('Yes', 'Yes'), ('No', 'No')], validators [InputRequired()])
#app.route("/some_page")
def some_page():
form = MyClass()
return render_template("some_page.html", form=form)
_render_field.html
{% macro render_radio_field(field) %}
<div class="form__item">
<label class="form__label">{{field.label.text }}</label>
<div class="form-group">
{{ field(class_='form__input', **kwargs)|safe }}
{% for subfield in field %}
<div class="form__item">
<label>
{{ subfield }}
{{ subfield.label.text }}
</label>
</div>
{% endfor %}
</div>
</div>
{% endmacro %}
some_page.html
{% from "_render_field.html" import render_field, render_radio_field %}
{% extends "layout.html" %}
{% block title %}My Title{% endblock %}
{% block content %}
<div style="width:600px; margin:0 auto;">
<h3>Some Text</h3>
<form class="form" action="{{url_for('some_page')}}" method="POST">
{% from "_render_field.html" import render_field, render_radio_field %}
{{ form.csrf_token }}
{{ render_field(my_field, title="", style="list-style:none") }}
{% if form.my_field.option == "Yes" %}
{{ render_field(form.some_other_StringField, placeholder="Please explain:", title="") }}
{% endif %}
<input type="submit" name="" value="login" class="form__btn">
</form>
</div>
{% endblock %}
def listing(request):
contact_list = Question.objects.all()
paginator = Paginator(contact_list, 1) # Show 25 contacts per page
page = request.GET.get('page')
contacts = paginator.get_page(page)
Let's say in each page I have a form, and when the form submitted I need to go to the next page.
I first tried to add a hidden field in the form, and manually calculate the next page, and put into HTTPResponseRedirect, but then I get an empty object error for the last page because of the following:
<input type="hidden" name="next" value="?page={{ contacts.next_page_number }}">
That page contains no results
{% for contact in contacts %}
{# Each "contact" is a Contact model object. #}
{{ contact.question_text|upper }}<br>
...
<form action="{% url 'listing' %}" method="post">
{% csrf_token %}
{% for choice in contact.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
<input type="hidden" name="next" value="?page={{ contacts.next_page_number }}">
{% endfor %}
<input type="submit" value="Vote">
</form>
{% endfor %}
<div class="pagination">
<span class="step-links">
{% if contacts.has_previous %}
« first
previous
{% endif %}
<span class="current">
Page {{ contacts.number }} of {{ contacts.paginator.num_pages }}.
</span>
{% if contacts.has_next %}
next
last »
{% endif %}
</span>
</div>
So what should be my strategy? Do I need to create a seperate view for form action, or should I use listing as form action and check wheter it is a GET/POST method, I am kind of lost here.
I am trying to create a multi-step form wizard using django-formtools. I have a main model called Report and several ModelForms as follows:
class ReportFormP1(forms.ModelForm):
class Meta:
model = Report
fields = [
'company',
'address_line_1',
'address_line_2',
'responsible_person',
'person_consulted',
'assessor_name',
'previous_assessment_date',
'review_date',
]
# section 1
class ReportFormP2(forms.ModelForm):
class Meta:
model = Report
fields = [
"premise_num_floors",
"premise_floor_area",
"premise_occupancy",
"premise_occupancy_comments",
]
in my views, I have created the following view:
class ReportWizardView(SessionWizardView):
template_name = 'reporting/report_create2.html'
form_list = [ReportFormP1, ReportFormP2]
def done(self, form_list, **kwargs):
return render(self.request, 'done.html', {
'form_data': [form.cleaned_data for form in form_list],
})
And my relevant template looks as follows:
{% extends '_base.html' %}
{% load static %}
{% load i18n %}
{% load crispy_forms_tags %}
<!-- templates/home.html -->
{% load socialaccount %}
{% block title %}Create a report{% endblock title %}
{% block extra_css %}
{{ wizard.form.media }}
{% endblock extra_css %}
{% block content %}
<div class="container">
<h1>Create a report</h1>
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action="" method="post">
{% csrf_token %}
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form|crispy }}
{% endfor %}
{% else %}
{{ wizard.form|crispy }}
{% endif %}
<div class="text-center">
{% if wizard.steps.prev %}
<button class="btn btn-lg btn-warning" name="wizard_goto_step" type="submit" value="{{ wizard.steps.first }}" formnovalidate>{% trans "first step" %}</button>
<button class="btn btn-lg btn-primary" name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}" formnovalidate>{% trans "prev step" %}</button>
{% endif %}
{% if wizard.steps.next %}
<button class="btn btn-lg btn-primary" name="wizard_goto_step" type="submit" value="{{ wizard.steps.next }}">{% trans "next step" %}</button>
{% endif %}
<input class="btn btn-lg btn-success" type="submit" name="Submit" value="Create report">
</div>
</form>
<hr>
<hr>
</div>
{% endblock content %}
My urls.py look as follows:
path('create_report2', ReportWizardView.as_view(), name="report_create2"),
My problem is that the form steps are not being saved when I click on next, and then previous (the form is valid). Bellow is an example
First form loaded:
(source: imge.to)
After clicking on 'next':
(source: imge.to)
Now when i click on 'previous', everything is gone:
(source: imge.to)
I wonder what I have missed?
As per Formtools documentation you need to Enable Session.
https://django-formtools.readthedocs.io/en/latest/wizard.html#formtools.wizard.views.SessionWizardView
i have a formset as follows:
EduFormSet = formset_factory(forms.CandidateDegreeForm, can_delete=True)
edu_formset = EduFormSet(prefix='candidate_degree')
in the templates i am doing the following:
{% if edu_formset %}
{% for form in edu_formset %}
<div class="formset-form" style="visibility: visible;">
<form id="{{ form.prefix }}" method="POST" action="/degree/add/">
<h4>Some Heading Here</h4>
{% csrf_token %}
{% for field in form %}
{% include "form_field.html" %}
{% endfor %}
</form>
<script type="text/javascript">
jQuery(document).ready ( function(){
jQuery('{{ form.prefix }}').validationEngine();
});
</script>
<div class="clearfix"></div>
</div>
{% endfor %}
{{ edu_formset.management_form }}
<div class="button-container right">
<input class="button" type="submit" value="submit" />
</div>
{% endif %}
I am not sure why but nothing really happens when i hit the submit button.
Your submit button is not within the form, so the action is not triggered by the click!
Here's how the docs show you to render formsets:
<form method="post" action="">
<!-- Notice how the formset (below) and thus its submit button
is INSIDE the form (above) -->
{{ formset.management_form }}
<table>
{% for form in formset %}
{{ form }}
{% endfor %}
</table>
</form>
You try to create multiple forms with the form.prefix for id. This could work but each form would have to be rendered with its own submit button. Formsets are designed to combine multiple forms into one and guarantee uniqueness of value names by said prefix. They would be enclosed in a singe form and share any submit triggers.