Question

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 %}
Was it helpful?

Solution 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.

OTHER TIPS

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>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top