django-formtools, saving data between form steps - django

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

Related

How to save form instance created using sessionwizard class in django?

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()

django: extending allauth.account

allauth.account comes with a signup.html
{% extends "account/base.html" %}
{% load i18n %}
{% block head_title %}{% trans "Signup" %}{% endblock %}
{% block content %}
<h1>{% trans "Sign Up" %}</h1>
<p>{% blocktrans %}Already have an account? Then please sign in.{% endblocktrans %}</p>
<form class="signup" id="signup_form" method="post" action="{% url 'account_signup' %}">
{% csrf_token %}
{{ form.as_p }}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<button type="submit">{% trans "Sign Up" %} »</button>
</form>
{% endblock %}
i would like to override it instead of using the form
what do i need to post to the url account_signup?
thank you
The 'account_signup' url is aimed to receive the POST request passing
at least the form fields marked as required in order to create an account.
But keep in mind that the name of the fields may vary based on the allauth settings.
I ended up doing the same thing, ealeon. Here is what I went with and it works well. Pardon the bootstrap classes, but you get the gist.
<form class="login" method="POST" action="{% url 'account_login' %}">
{% csrf_token %}
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.login.errors }}
{{ form.login }}
</div>
<div class="fieldWrapper">
{{ form.password.errors }}
{{ form.password }}
</div>
<div class="login-options pull-left">
{{ form.remember.errors }}
<label for="{{ form.remember.id_for_label }}">Stay signed in?</label>
{{ form.remember }}
</div>
<div class="login-options pull-right">
<a class="button secondaryAction"
href="{% url 'account_reset_password' %}">
{% trans "Forgot Password?" %}
</a>
</div>
<button class="btn btn-block btn-primary" type="submit">{% trans "Sign In" %}</button>
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
</form>

How can I use django-userena login and logout forms in every page with djangocms?

I have a site running with djangocms and I need the login and logout capabilities of django-userena, it's easy for me to use this because every user will have a profile page too. The design for the menu in every page states that a simple login form has to be in the top right corner of the menu. I have already done that, but I need the django-userena login to work with it. How can I do it?
I have tried to add the form in my base.html. Also tried with a middleware.py like this
class LoginFormMiddleware(object):
def process_request(self, request):
from userena.forms import AuthenticationForm
if request.method == 'POST' and request.POST.has_key('base-account') and request.POST['base-account'] == 'Login':
form = AuthenticationForm(data=request.POST, prefix="login")
if form.is_valid():
from django.contrib.auth import login
login(request, form.get_user())
request.method = 'GET'
else:
form = AuthenticationForm(request, prefix="login")
request.login_form = form
class LogoutFormMiddleware(object):
def process_request(self, request):
if request.method == 'POST' and request.POST.has_key('base-account') and request.POST['base-account'] == 'Logout':
from userena.views import signout
signout(request)
request.method = 'GET'
base.html
<form class="navbar-form navbar-right login-strip" action="" method="post">
{% csrf_token %}
<p id="login">
{{ request.login_form.non_field_errors }}
{% for field in request.login_form %}
{{ field.errors }}
{{ field.label_tag}}: {{ field }}
{% endfor %}
<input type="submit" name="base-account" value="Login" />
</p>
</form>
{% else %}
<form class="navbar-form navbar-right login-strip" action="" method="post">
{% csrf_token %}
<p id="logout">Logged in as <b>{{ request.user.username }}</b>.
<input type="submit" name="base-account" value="Logout" />
</p>
</form>
{% endif %}
This gives me this error
'WSGIRequest' object has no attribute 'get'
I have tried a lot of thighs in this.
Now I'm not using any side django-authetication I just put some code in my menu.html this way I can login and log out as need.
My problem was the normal account has no way to logout.
My work around is that:
menu.html
{% load i18n menu_tags cache %}
{% for child in children %}
<li class="{% if child.ancestor %}ancestor{% endif %}
{% if child.selected %} active{% endif %}
{% if child.children %} dropdown{% endif %}">
{% if child.children %}
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
{{ child.get_menu_title }} <span class="caret"></span>
</a>
<ul class="dropdown-menu">
{% show_menu from_level to_level extra_inactive extra_active template "" "" child %}
</ul>
{% else %}
<span>{{ child.get_menu_title }}</span>
{% endif %}
</li>
{% if class and forloop.last and not forloop.parentloop %}{% endif %}
{% endfor %}
<li class="User" style="position: absolute; right: 0;">
<a >
{% if user.is_authenticated %}
<form method="post" action= "accounts/logout/?next={{ request.path }}">
{% csrf_token %}
<button type="submit" class="cms-btn cms-btn-action"><span class="glyphicon glyphicon-user"></span> {{ request.user.username }}</button>
</form>
{% else %}
<form action="{% url 'pages-root' %}{% if request.path != logout_url %}?next={{ request.path }}&{{ cms_edit_on }}&cms-toolbar-login=1{% endif %}"
class="cms-toolbar-item cms-form-login" method="post">
{% csrf_token %}
<label{% if request.toolbar.login_form.username.errors or request.toolbar.login_form.non_field_errors or cms_toolbar_login_error %} class="cms-error"{% endif %}>
<span>{% trans request.toolbar.login_form.username.label %}</span>
{{ request.toolbar.login_form.username }}
</label>
<label{% if request.toolbar.login_form.password.errors or request.toolbar.login_form.non_field_errors or cms_toolbar_login_error %} class="cms-error"{% endif %}>
<span>{% trans request.toolbar.login_form.password.label %}</span>
{{ request.toolbar.login_form.password }}
</label>
<label>
<input class="cms-btn cms-btn-action" type="submit" value="{% trans 'Login' %}">
</label>
</form>
{% endif %}
</a>
</li>
urls.py added this:
url(r'^accounts/', include('django.contrib.auth.urls')),
I end up with this code, more mobile friend.
<li class="User" style="position: absolute; right: 0;">
<a >
{% if user.is_authenticated %}
<form method="post" action= "accounts/logout/?next={{ request.path }}">
{% csrf_token %}
<p id="logout"><span class="glyphicon glyphicon-user"></span> <b>{{ request.user.username }}</b>
<button type="submit" class="cms-btn cms-btn-action"><span class="glyphicon glyphicon-off"></span> {% trans "Logout" %}</button>
</form>
{% else %}
<form method="post" action="{{request.path}}?edit">
{% csrf_token %}
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-user"></span> {% trans "Login" %}</button>
</form>
{% endif %}
</a>
</li>

django form wizard, does not go to second step

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

Django is not loading template form

I don't know why is not loading the template but every time I click in an url the page auto-reload and not load the template, here is my code:
urls.py
url(r'^pedidos/add',forms.PedidoCreateView.as_view(), name="pedido_add")
forms.py
class PedidoCreateView(CreateView):
template_name = 'ventas/form_pedido.html'
model = Pedido
form_class = PedidoModelForm
success_url = 'ventas/pedidos.html'
def form_valid(self, form):
form.save(commit=True)
return super(PedidoCreateView, self).form_valid(form)
form_pedido.html
{% extends '_layouts/base.html' %}
{% load url from future %}
{% block breadcrumb%}
<li>
Pedidos
<span class="divider">
<i class="icon-angle-right"></i>
</span>
</li>
<li class="active">Nuevo Pedido</li>
{% endblock %}
{% block page_content %}
<form class ="form" id="form" method="POST" action="{{ request.path }}">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3>Editar Empleado</h3>
</div>
<div class="modal-body">
{% csrf_token %}
{{ form.non_field_errors }}
{{ form_errors }}
{{form.as_p}}
</div>
<div class="modal-footer">
Cerrar
<input type="submit" class="guardar btn btn-primary" value="Guardar">
</div>
</form>
{% endblock %}
{% block scripts %}
{% endblock %}
link
<a href="{% url 'ventas:pedido_add' %}" class="btn btn-app btn-success">
For sure has to be some error that I'm not able to see now, I prove with other similar views and I don't have any problems, what could it be?