This problem is due to validation done in javascript. Not related to django form wizard or django as such.
You may want to disable it or skip in particular case.
题
I have a multi step form which is built using sessionwizardview
of django form wizard, I have added next and previous buttons, but the problem is, if I am in a step and when I click previous, it asks for the form to be filled up first and then could proceed and go to previous step on click of that previous button. I am clueless as I couldnt find anything related to my problem, am I missing something?
Here are couple of sample forms:
from django import forms
from django.utils.translation import gettext as _
from addresses.forms import AddressForm, InvoiceAddressForm
from core.api import NcpAPI
from django_countries import countries
api = NcpAPI()
CHOICES=[('0','Pay by card'), ('1','Invoice')]
class RegistrationForm(forms.Form):
title = 'registration'
first_name = forms.CharField(label=_("First Name"), widget=forms.TextInput(attrs={'class':'form-text required'}))
last_name = forms.CharField(label=_("Last Name"), widget=forms.TextInput(attrs={'class':'form-text required'}))
registration_company = forms.CharField(label=_("Company"), widget=forms.TextInput(attrs={'class':'form-text required'}))
phone = forms.CharField(label=_("Phone"), widget=forms.TextInput(attrs={'class':'form-text required'}))
email = forms.EmailField(label=_("Email"), widget=forms.TextInput(attrs={'class':'form-text required'}))
def clean_email(self):
email = self.cleaned_data.get('email')
if api.is_username_taken(email):
raise forms.ValidationError(_('Email is in use'))
return email
class AddressesForm(InvoiceAddressForm, AddressForm):
title = 'addresses'
class PaymentForm(forms.Form):
title = 'payment'
payment_method = forms.ChoiceField(label = _("Payment Options"), choices=CHOICES, widget=forms.RadioSelect(attrs={'class':'form-text required'}), required = True, initial = "1")
class ConfirmationForm(forms.Form):
title = 'confirm'
And here is my session wizard class:
class SubscriptionWizard(SessionWizardView):
def get_template_names(self):
return [TEMPLATES.get(self.steps.current)]
extra_data = {}
def get_context_data(self, form, **kwargs):
pp = pprint.PrettyPrinter(indent=4)
context = super(SubscriptionWizard, self).get_context_data(form=form, **kwargs)
context.update(self.extra_data)
data = self.get_all_cleaned_data()
context['all_data'] = {"product":self.kwargs['product']}
# if self.steps.current == 'addresses':
# print ' yes its addresses %s' % data.get('company')
# context['all_data'].update({"reg_company":data.get('company')})
if self.steps.current in ('payment', 'confirm'):
if data[u'invoice_name'] != '':
p = Prices.objects.filter(name = self.kwargs['product'], currency = str(self.getCurrencyCode(str(data[u'invoice_country']))) )
else:
p = Prices.objects.filter(name = self.kwargs['product'], currency = str(self.getCurrencyCode(data.get('country'))) )
context['all_data']['product_price'] = p[0].price
context['all_data']['product_currency'] = p[0].currency
if data.get('invoice_name'):
currency_country = data.get('invoice_country')
else:
currency_country = data.get('country')
if self.steps.current == 'confirm':
p = Prices.objects.filter(name = self.kwargs['product'], currency = str(self.getCurrencyCode(data.get('country'))) )
context['all_data']['product_price'] = p[0].price
context['all_data']['product_currency'] = p[0].currency
if data:
# pp.pprint(data)
context['all_data'].update(data)
# pp.pprint(context['all_data'])
return context
def get_form_initial(self, step):
initial = self.initial_dict.get(step, {})
if 'profiler' in self.request.session and step in ('registration', 'address', 'payment'):
profiler = self.request.session.get('profiler')
data = {}
if step == 'registration':
# pp = pprint.PrettyPrinter(indent=4)
# pp.pprint(profiler.user.account.account)
# print profiler.user.account
data = {'email': profiler.user.account.email ,
'first_name':profiler.user.account.firstName if profiler.user.account.account.firstName != '' else '',
'last_name':profiler.user.account.lastName,
'phone': profiler.user.account.phone1 if profiler.user.account.account.firstName != '' else ''}
initial.update(data)
return initial
def get_form(self, step=None, data=None, files=None):
form = super(SessionWizardView, self).get_form(step, data, files)
if hasattr(form, 'initialize_wizard'):
form.initialize_wizard(self)
return form
def getCurrencyCode(self, countryCode):
continent = transformations.cca_to_ctn(countryCode)
# print continent
if str(countryCode) == 'NO':
return 'NOK'
if str(countryCode) == 'GB':
return 'GBP'
if (continent == 'Europe') or (continent == 'Africa'):
return 'EUR'
return 'USD'
def done(self, form_list, **kwargs):
pp = pprint.PrettyPrinter(indent=4)
import hashlib
data = dict(('%s_%s' % (form.prefix,k),v) for form in form_list for k, v in form.cleaned_data.items())
# print 'print data ....'
# print ''
# print ''
# pp.pprint(data)
# print ''
# print ''
# print ''
# print '--------------'
# print data
full_name = "%s %s" % (data['registration_first_name'],data['registration_last_name'])
data['product'] = kwargs['product']
dumps = simplejson.dumps(data)
data['country_label']=unicode(fields.Country(data['addresses_country']).name)
print data
if data.get('invoice_name'):
currency_country = data.get('addresses_invoice_country')
else:
currency_country = data.get('addresses_country')
currencyCode = self.getCurrencyCode(currency_country)
prices = Prices.objects.filter(name = kwargs['product'], currency = str(currencyCode))
data['product_price'] = prices[0].price
data['product_currency'] = str(currencyCode)
# print currencyCode
include_archive = 'standard' in kwargs.values()
# Register.
# print 'print data before registering the product ....'
# print ''
# print ''
# pp.pprint(data)
# print ''
# print ''
# print ''
# print '--------------'
result = api.subscribe_to_product(subscribe_to_archive=include_archive, **data)
if 'errorCode' in result:
messages.add_message(self.request, messages.ERROR, _('The registration was not successfull.'))
return render(self.request, 'subscription_product/failed.html', {'clean_data': data})
print '--------'
cs_message = render_to_string(
'subscription_product/email/registered_cs.html', {'data':data})
print api.email(settings.EMAIL_CS_NAME, settings.EMAIL_CS_EMAIL, "Registration for %s" % data['product'], cs_message)
# Save subscription.
s = SubscriptionInfo(subscriptionId = str(result[u'subscriptionId']), customerNumber = result[u'customerNumber'],subscriptionType = str(data['product']), currency = str(currencyCode))
s.save()
if int(data['payment_payment_method']) == 1:
# Sends activation email.
token = api.create_token(7200, 99,'productSub', data['registration_email']).get('tokenValue', '')
activation_url = Site.objects.get_current().domain + reverse("activation_home", kwargs={'token':token})
# activation_url = 'http://localhost:8080' + reverse("activation_home", kwargs={'token':token})
# full_name = '%s %s' % (data.get('registration_first_name'), data.get('registration_last_name'))
customer_message = render_to_string(
'subscription_product/email/registered_customer.html', {'activation_url':activation_url})
print api.email("%s %s" % (data['registration_first_name'], data['registration_last_name']), data['registration_email'], "Your Tradewindsnews.com order registration", customer_message)
#SEND EMAIL TO SALES ON SUCCESS
sales_message = render_to_string(
'subscription_product/email/invoice_sales_success.html',
{'customer_name': full_name,
'account': data,
'alternative_invoice_company':data['addresses_invoice_company'],
'alternative_invoice_street':data['addresses_invoice_street'],
'alternative_invoice_city':data['addresses_invoice_city'],
'alternative_invoice_postal_code':data['addresses_invoice_postal_code'],
'alternative_invoice_country':data['addresses_invoice_country'],
'payment_date': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
'amount': float(prices[0].price),
'currency' : currencyCode,
'transactionid' :'',
'authorizationid' : '',
'confirmation_number': ''})
api.email("%s %s" % (data['registration_first_name'], data['registration_last_name']), settings.EMAIL_SALES, "New Subscription Order", sales_message)
return render(self.request, 'subscription_product/receipt.html', {'clean_data': data})
else:
site_url = "http://%s" % Site.objects.get(name='secondary')
# site_url = "http://localhost:8000"
# dumps = simplejson.dumps(data)
p = PaymentBeforeDump(dump = dumps, subscriptionInfo = s)
p.save()
# prices = Prices.objects.get(name = kwargs['product'])
return HttpResponseRedirect(
Register(
p_request_Order_Amount = int(float(prices[0].price)*100),
p_request_Order_CurrencyCode = currencyCode,
p_request_Order_OrderNumber = hashlib.md5("foobar" + str(time.time())).hexdigest(),
p_request_Terminal_RedirectUrl = site_url + reverse("subscription_product_payment_return",kwargs={'amount':int(float(prices[0].price)*100), 'currency': str(currencyCode), 'subscription': kwargs['product'], 'id':p.id}),
p_request_TransactionReconRef = 'tw-random',
)
)
And here is one template:
{% extends "base.html" %}
{% load url from future %}
{% load i18n %}
{% load subscription_product_tags %}
{% block content %}
<section class="topsection group">
<div class="col span_3_of_3 first-child last-child">
<div class="order">
<ol class="steps">
<li class="done">Subscription</li>
<li class="done">Details</li>
<li class="done">Delivery</li>
<li class="active">Payment</li>
<li class="queue">Confirm</li>
<li class="queue">Receipt</li>
</ol>
<div class="box">
<section class="section group first-child">
<h1>Payment Summary</h1>
Please review the following details for this transaction.
</section>
<section class="topsection group">
<table border="1">
<tr>
<th>
Description
</th>
<th>
Item Price
</th>
</tr>
<tr>
{% comment %}get the pricing and other product related info{% endcomment %}
{{ all_data|product_price_info|safe }}
</tr>
</table>
</section>
<form action="" method="post">{% csrf_token %}
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form }}
{% endfor %}
{% else %}
<section class="topsection group">
{{ wizard.form.payment_method.label_tag }}
{{wizard.form.payment_method}}
{{ wizard.form.payment_method.errors}}
</section>
{%endif %}
<section class="section group last-child">
<div class="col span_3_of_3 first-child last-child">
<fieldset class="form-actions">
<!-- <a class="backbutton" onClick="goPrevious()">Previous</a> -->
{# <button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">{% trans "Previous" %}</button> #}
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">{% trans "Previous" %}</button>
<input type="submit" value="Next">
</fieldset>
</div>
</section>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
{% block customerservice %}{% endblock %}
{% block footer %}{% endblock %}
解决方案 3
This problem is due to validation done in javascript. Not related to django form wizard or django as such.
You may want to disable it or skip in particular case.
其他提示
Perhaps, it will help someone.
I am using Django with https://django-formtools.readthedocs.io/en/latest/wizard.html using bootstrap. I've got same problem as OP, but I didn't have active JS. In my case, solution was to add formnovalidate="formnovalidate" to template.
{% if wizard.steps.prev %}
<button formnovalidate="formnovalidate" name="wizard_goto_step" value="{{ wizard.steps.first }}">
first step
</button>
<button formnovalidate="formnovalidate" name="wizard_goto_step" value="{{ wizard.steps.prev }}">
prev step
</button> {% endif %}
Hope it helps.
HTML5 includes the formnovalidate
attribute which you can use to skip validation. In the case of Form Wizard, to skip validation when going to the previous step, just include the formnovalidate
attribute to the corresponding button. For example (snippet taken from documentation):
<form action="" method="post">{% csrf_token %}
<table>
{{ wizard.form }}
</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 }}" formnovalidate>{% trans "prev step" %}</button>
{% endif %}
<input type="submit" value="{% trans "submit" %}"/>
</form>