Django: formset errors without li / * - django

I am using a formset. formset.non_form_errors are displayed exactly the way I need it. However my field specific errors in for dict in formset.errors are always displayed inlcuding the <li> tag. I tried .as_text, however that just added a * (and removed the li). But I don't need the * either.
Anyone who can help me with that?
{% if formset.total_error_count %}
{% if formset.non_form_errors %}
{% for error in formset.non_form_errors %}
<div class="alert alert-warning" role="alert">
{{ error|escape }}
</div>
{% endfor %}
{% endif %}
{% for dict in formset.errors %}
{% for error in dict.values %}
<div class="alert alert-warning" role="alert">
{{ error|escape }}
</div>
{% endfor %}
{% endfor %}
{% endif %}
<form method="post">
{% csrf_token %}
{{ formset.management_form }}

The problem could be fixed by moving the individual errors in the form loop:
{% if formset.total_error_count %}
{% if formset.non_form_errors %}
{% for error in formset.non_form_errors %}
<div class="alert alert-warning" role="alert">
{{ error|escape }}
</div>
{% endfor %}
{% endif %}
{% endif %}
{% for form in formset %}
{% if form.quantity.errors %}
<div class="alert alert-warning" role="alert">
{% for error in form.quantity.errors %}
{{ error|escape }}
{% endfor %}
</div>
{% endif %}

Related

Validation of checkbox in Shopware 6 only working upon up and down scroll

I moved the terms and conditions consent from the original twig template so that it shows at a different position on the website. My problem is that when the consent checkbox is not checked, a warning should be shown to the user when clicking the payment button. This however only happens, when scrolling up and down on the website after clicking the finish payment button. Does anyone see my mistake?
{% sw_extends '#Storefront/storefront/page/checkout/confirm/index.html.twig' %}
{% block base_header %}
{% sw_include '#Storefront/storefront/layout/header/header-minimal.html.twig' %}
{% endblock %}
{% block base_navigation %}{% endblock %}
{% block page_checkout_main_content %}
{% block page_checkout_confirm %}
{% block page_checkout_confirm_header %}
<h1 class="confirm-main-header">
{{ "checkout.confirmHeader"|trans|sw_sanitize }}
</h1>
{% endblock %}
{% block page_checkout_confirm_alerts %}
{% block page_checkout_confirm_violations %}
{% for violation in formViolations.getViolations() %}
{% set snippetName = "error.#{violation.code}" %}
{% set fieldName = violation.propertyPath|trim('/', 'left') %}
{% sw_include '#Storefront/storefront/utilities/alert.html.twig' with {
type: "danger",
content: snippetName|trans({'%field%': fieldName})|sw_sanitize
} %}
{% endfor %}
{% endblock %}
{% endblock %}
{% block page_checkout_confirm_address %}
<div class="confirm-address">
{% sw_include '#Storefront/storefront/page/checkout/confirm/confirm-address.html.twig' %}
</div>
{% endblock %}
{% block page_checkout_confirm_payment_shipping %}
<div class="confirm-payment-shipping">
<div class="row">
{% block page_checkout_confirm_payment %}
<div class="col-sm-6 confirm-payment">
{% sw_include '#Storefront/storefront/page/checkout/confirm/confirm-payment.html.twig' %}
</div>
{% endblock %}
{% block page_checkout_confirm_shipping %}
<div class="col-sm-6 confirm-shipping">
{% sw_include '#Storefront/storefront/page/checkout/confirm/confirm-shipping.html.twig' %}
</div>
{% endblock %}
</div>
</div>
{% endblock %}
{% block page_checkout_confirm_product_table %}
<div class="confirm-product">
{% block page_checkout_confirm_table_container %}
<div class="card">
<div class="card-body">
{% block page_checkout_confirm_table_header %}
{% sw_include '#Storefront/storefront/page/checkout/confirm/confirm-product-header.html.twig' %}
{% endblock %}
{% block page_checkout_confirm_table_items %}
{% for lineItem in page.cart.lineItems %}
{% block page_checkout_confirm_table_item %}
{% sw_include '#Storefront/storefront/page/checkout/confirm/confirm-item.html.twig' %}
{% endblock %}
{% endfor %}
{% endblock %}
</div>
</div>
{% endblock %}
</div>
{% endblock %}
{% block page_checkout_confirm_tos %}
<div class="confirm-tos">
<div class="card checkout-card">
<div class="card-body">
{% block page_checkout_confirm_tos_header %}
<div class="card-title">
{{ "checkout.confirmTermsHeader"|trans|sw_sanitize }}
</div>
{% endblock %}
{% block page_checkout_confirm_revocation_notice %}
{% if config('confirm.revocationNotice') %}
<p class="revocation-notice">
{% block page_checkout_confirm_revocation_notice_link %}
<a href="{{ path('frontend.cms.page',{ id: config('core.basicInformation.revocationPage') }) }}"
{{ dataBsToggleAttr }}="modal"
title="{{ "checkout.confirmRevocationNotice"|trans|striptags }}"
data-url="{{ path('frontend.cms.page',{ id: config('core.basicInformation.revocationPage') }) }}">
{{ "checkout.confirmRevocationNotice"|trans|sw_sanitize }}
</a>
{% endblock %}
</p>
{% endif %}
{% endblock %}
{% block page_checkout_confirm_tos_control %}
<div class="{{ formCheckboxWrapperClass }}">
{% block page_checkout_confirm_tos_control_checkbox %}
<input type="checkbox"
class="checkout-confirm-tos-checkbox {{ formCheckInputClass }}{% if formViolations.getViolations('/tos') is not empty %} is-invalid{% endif %}"
required="required"
id="tos"
form="confirmOrderForm"
name="tos"/>
{% endblock %}
{% block page_checkout_confirm_tos_control_label %}
<label for="tos"
class="checkout-confirm-tos-label custom-control-label">
{{ "checkout.confirmTerms"|trans({
'%url%': path('frontend.cms.page',{ id: config('core.basicInformation.tosPage') })
})|raw }}
</label>
{% endblock %}
</div>
{% endblock %}
</div>
</div>
</div>
{% endblock %}
{% block page_checkout_confirm_hidden_line_items_information %}
{% sw_include '#Storefront/storefront/component/checkout/hidden-line-items-information.html.twig' with {
cart: page.cart,
lineItems: page.cart.lineItems
} %}
{% endblock %}
{% endblock %}
{% endblock %}
{% block page_checkout_additional %}
{% if config('core.cart.showCustomerComment') %}
<div class="checkout-additional">
{% block page_checkout_finish_customer_comment %}
<div class="card checkout-card">
<div class="card-body">
{% block page_checkout_confirm_customer_comment_header %}
<div class="card-title">
{{ "checkout.customerCommentHeader"|trans|sw_sanitize }}
</div>
{% endblock %}
{% block page_checkout_confirm_customer_comment_control %}
<div class="checkout-customer-comment-control">
{% block page_checkout_confirm_customer_comment_control_textfield_label %}
<label class="form-label" for="{{ constant('Shopware\\Core\\Checkout\\Order\\SalesChannel\\OrderService::CUSTOMER_COMMENT_KEY') }}">
{{ "checkout.customerCommentLabel"|trans|sw_sanitize }}
</label>
{% endblock %}
{% block page_checkout_confirm_customer_comment_control_textfield %}
<textarea class="form-control"
placeholder="{{ "checkout.customerCommentPlaceholder"|trans|sw_sanitize }}"
id="{{ constant('Shopware\\Core\\Checkout\\Order\\SalesChannel\\OrderService::CUSTOMER_COMMENT_KEY') }}"
form="confirmOrderForm"
name="{{ constant('Shopware\\Core\\Checkout\\Order\\SalesChannel\\OrderService::CUSTOMER_COMMENT_KEY') }}"></textarea>
{% endblock %}
</div>
{% endblock %}
</div>
</div>
{% endblock %}
</div>
{% endif %}
{% endblock %}
{% set formAddHistoryOptions = {
entries: [{
state: {},
title: 'account.ordersTitle'|trans,
url: path('frontend.account.order.page')
}]
} %}
{% block page_checkout_aside_actions %}
<div class="checkout-aside-action">
<form id="confirmOrderForm"
action="{{ path('frontend.checkout.finish.order') }}"
data-form-csrf-handler="true"
data-form-preserver="true"
data-form-submit-loader="true"
data-form-add-history="true"
data-form-add-history-options='{{ formAddHistoryOptions|json_encode }}'
method="post">
{% block page_checkout_aside_actions_csrf %}
{{ sw_csrf('frontend.checkout.finish.order') }}
{% endblock %}
{% block page_checkout_confirm_form_submit %}
{# #deprecated tag:v6.5.0 - Bootstrap v5 removes `btn-block` class, use `d-grid` wrapper instead #}
{% if feature('v6.5.0.0') %}
<div class="d-grid">
<button id="confirmFormSubmit"
class="btn btn-primary btn-lg"
form="confirmOrderForm"
{% if page.cart.errors.blockOrder %}
disabled
{% endif %}
type="submit">
{{ "checkout.confirmSubmit"|trans|sw_sanitize }}
</button>
</div>
{% else %}
<button id="confirmFormSubmit"
class="btn btn-primary btn-block btn-lg"
form="confirmOrderForm"
{% if page.cart.errors.blockOrder %}
disabled
{% endif %}
type="submit">
{{ "checkout.confirmSubmit"|trans|sw_sanitize }}
</button>
{% endif %}
{% endblock %}
</form>
</div>
{% endblock %}
{% block base_footer %}
{% sw_include '#Storefront/storefront/layout/footer/footer-minimal.html.twig' %}
{% endblock %}

Using a custom form inside django wizard

How would I use a custom form to display inside the session wizard so when it goes through each step it displays the html for each form inside the signup.html.
createUser.html
{% extends 'base.html' %}
{% block title %}Create User{% endblock %}
{% block content %}
<form method="POST" action='.' enctype="multipart/form-data">
{% csrf_token %}
<!-- A formwizard needs this form -->
{{ wizard.management_form }}
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% if field.help_text %}
<small style="color: grey">{{ field.help_text }}</small>
{% endif %}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button>Sign up</button>
<button>Log In</button>
</form>
{% endblock %}
views.py
class UserWizard(SessionWizardView):
template_name = "registration/signup.html"
form_list = [SignUpForm]
def done(self, form_list, **kwargs):
process_data(form_list)
return redirect('home')
signup.html
{% extends 'base.html' %}
{% load i18n %}
{% block head %}
{{ wizard.form.media }}
{% endblock %}
{% block title %}Sign up{% endblock %}
{% block content %}
<h2>Sign up</h2>
<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.prev }}">{% trans "prev step" %}</button>
{% endif %}
<input type="submit" value="{% trans 'submit' %}"/>
</form>
{% endblock %}

How to exclude specific field types in a template form loop

I am using django_widget_tweaks to loop over form fields:
{% for field in form.visible_fields %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{% if form.is_bound %}
{% if field.errors %}
{% render_field field class="form-control is-invalid" %}
{% for error in field.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>
{% endfor %}
This displays a happy Bootstrap4 compliant interface, except when displaying fields like radio when I need to use a custom-control class not the form-control class.
How can I filter the form field loop to exclude radio inputs so I can write this code separately?
I need to understand how to filter the field loop and what the correct way to do this with the field type for radio is.

Django Formset field label in error messages

Is there a simple way to get the field label in an error message for a Django formset. I am able to do it in a normal form like so:
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ field.label }}: {{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}
However, I'd like the same thing for the formset. The closest I've gotten is
{% if formset.errors %}
{% for dict in formset.errors %}
{% for field, error in dict.items %}
<div class="alert alert-danger">
<strong>{{ field }}: {{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% endfor %}
{% for error in formset.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}
However, this gives me the field name (e.g. pub_date) instead of the label (e.g. Publication Date). Any help much appreciated!
I can't see a simple way to get from the field string to the field instance in a template, so you may have to iterate over forms and fields instead of formset.errors:
{% if formset.errors %}
{% for form in formset %}
{% for field in form %}
{% if field.errors %}
<div class="alert alert-danger">
<strong>{{ field.label }}: {{ field.errors|escape }}</strong>
</div>
{% endif %}
{% endfor %}
{% endfor %}
{% for error in formset.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}

Django: how to use a template tag as an arguments for another template tag

I need to use a template tag inside another tag that is a custom tag and it gives me this error:
Could not parse the remainder: '{{message.tags}}' from '{{message.tags}}'
How can I fix this? TIA for any help!
template.html:
<div class="bootstrap-iso">
{% if messages %}
<div class="messages ">
{% for message in messages %}
<div {% if message.tags %} class="alert {{ message.tags }} alert-dismissible" role="alert" {% endif %}>
<strong> {% get_message_print_tag {{message.tags}} %}: </strong>
{{ message }}
×
</div>
{% endfor %}
</div>
{% endif %}
</div>
If you are using template tags in delemeters "{% %}" you don't have to use "{{}}".
<div class="bootstrap-iso">
{% if messages %}
<div class="messages ">
{% for message in messages %}
<div {% if message.tags %} class="alert {{ message.tags }} alert-dismissible" role="alert" {% endif %}>
<strong> {% get_message_print_tag message.tags %}: </strong>
{{ message }}
×
</div>
{% endfor %}
</div>
{% endif %}
</div>
hope this will work.