Add unique styling to one form in a Django formset - django

I have a formset with four forms, and want to render the fourth one with different CSS from the others - unique color, styling, etc. Can I do this from my html page, or somewhere else?
I'm looking for something like this pseudo-code:
<form action="" method="post">{% csrf_token %}
{{ formset.management_form }}
{{ formset.non_form_errors }}
<div>
{% for form in formset except the last form %}
{% for field in form %}
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
{% endfor %}
{% endfor %}
{% for the last form in the formset %}
{% for field in form %}
{{ field.errors }}
<div class="different style">
{{ field.label_tag }}:
<p class="another different style">{{ field }}</p>
</div>
{% endfor %}
{% endfor %}
</div>
<p><input type="submit" value="Submit" /></p>
</form>

See forloop.last in documentation -
<form action="" method="post">{% csrf_token %}
{{ formset.management_form }}
{{ formset.non_form_errors }}
<div>
{% for form in formset %}
{% if forloop.last %}
{% for field in form %}
{{ field.errors }}
<div class="different style">
{{ field.label_tag }}:
<p class="another different style">{{ field }}</p>
</div>
{% endfor %}
{% else %}
{% for field in form %}
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
{% endfor %}
{% endif %}
</div>
<p><input type="submit" value="Submit" /></p>
</form>

Related

How do I change the Django form.errors display text?

I want to remove the circled bit from being displayed. How would I be able to do this?
{% if form.errors %}
<div class="alert alert-warning alert-dismissible fade show"
role="alert">
<p class="m-0">{{ form.errors }}</p>
<button type="button"
class="btn-close"
data-bs-dismiss="alert"
aria-label="Close">
</button>
</div>
{% endif %}
This always displays
property where the error is found
error message
error message ...
I want to remove the property where the error is found. How would I do this?
Django Form has two error handlers:
Form.errors are field errors. By default, a dict of key "field name" : value "field errors"
Form.non_field_errors are general errors that have no relation to a field name, mainly errors from the Form.clean(..) method.
So you are trying to do an anti-pattern and a distraction to the user experience. Therefore you can best achieve a better experience by mapping each field to its value without the need to render the field name in the error.
Form custom rendering will give you full access to the Form API, and allow you to display the error in the way you like without the default render, something like the following looping over form's fields:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
By doing the above, you will also need to render the non_field errors, and the complete HTML tags will be as follows:
{{ form.non_field_errors }}
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
Django also offers manual render for each field something like the following:
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="{{ form.subject.id_for_label }}">Email subject:</label>
{{ form.subject }}
</div>
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="{{ form.message.id_for_label }}">Your message:</label>
{{ form.message }}
</div>
<div class="fieldWrapper">
{{ form.sender.errors }}
<label for="{{ form.sender.id_for_label }}">Your email address:</label>
{{ form.sender }}
</div>
<div class="fieldWrapper">
{{ form.cc_myself.errors }}
<label for="{{ form.cc_myself.id_for_label }}">CC yourself?</label>
{{ form.cc_myself }}
</div>
Choose the best fit for your needs.
There is still a hacky thing you can do which is not a best practice and will lead to conflicts between Field validation and non-field validation as follows Getting a list of errors in a Django form:
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% endif %}
In Django 4.0 or high
{% if form.errors %}
{% for error in form.errors.as_data.values %}
{% for data in error.0 %}
{{ data }}
{% endfor %}
{% endfor %}
{% endif %}

How to show validation errors in template using CreateView Django

I am using an extended User model and a generic CreateView.
class SignUp(CreateView):
form_class = forms.SignUpForm
success_url = '/accounts/login/'
template_name = 'accounts/signup.html'
How do I access the form validation errors in my template? They must be there because when I do {{ form.as_p }} the errors show up. I have tried {{ form.errors }} and {{ field.errors }} but there is nothing in them. Is there a simple tag I can call in my template to show the errors? Thanks.
you can do it manually if you like. Each field is available as an attribute of the form using {{ form.name_of_field }}, and in a Django template, will be rendered appropriately. For example:
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="{{ form.subject.id_for_label }}">Email subject:</label>
{{ form.subject }}
</div>
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="{{ form.message.id_for_label }}">Your message:</label>
{{ form.message }}
</div>
<div class="fieldWrapper">
{{ form.sender.errors }}
<label for="{{ form.sender.id_for_label }}">Your email address:</label>
{{ form.sender }}
</div>
<div class="fieldWrapper">
{{ form.cc_myself.errors }}
<label for="{{ form.cc_myself.id_for_label }}">CC yourself?</label>
{{ form.cc_myself }}
</div>
and if you want to loop all errors once on the top page.
{% if form.non_field_errors %}
<ul>
{% for error in form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
If you’re using the same HTML for each of your form fields, you can reduce duplicate code by looping through each field in turn using a {% for %} loop:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
you can check many methods to do that in Django documentation in the below URL
https://docs.djangoproject.com/en/4.0/topics/forms/#looping-over-the-form-s-fields

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 can I show help_text attribute through for loop in my template?

forms.py
class UserRegistratiion(forms.Form):
email = forms.EmailField()
name = forms.CharField(help_text="80 Char Maximum")
views.py
def showFormData(request):
fm = UserRegistratiion(auto_id="my_%s")
return render(request, "blog/login.html", {"form":fm})
When i use this in my template it works fine and my help_text shows in span tag..
<form action="">
<div>
{{form.as_p}}
</div>
But, whwn i use for loop
{% for field in form.visible_fields %}
<div>
{{field.label_tag}}
{{field}}
</div>
{% endfor %}
help_text doesn't show how can i get this?
try this
{% for field in form.visible_fields %}
<div>
{{ field.label_tag }}
{{ field }}
{{ field.help_text }} <!-- new -->
</div>
{% endfor %}
or
{% for field in form.visible_fields %}
<div>
{{ field.label_tag }}
{{ field }}
{% if field.name =='name' %}
{{ field.help_text }} <!-- new -->
{% endif %}
</div>
{% endfor %}

How to render form.errors without html tag

i want to render form.errors individually without the html tag but it doesn't seem to work
views.py
....
context = {
'login_error': form.errors,
'login_form': LoginForm(),
}
return render(request, 'shop/login.html', context)
....
login.html
....
<label class="mt-1"> {{ login_form.username.label }} </label>
{{ login_form.username }}
{{ login_error.username }}
<label class="mt-1"> {{ login_form.password.label }} </label>
{{ login_form.password }}
{{ login_error.password }}
....
the answer i got is by unpacking it in a loop and then add an |escape
....
{% for error in login_error %}
{{ error|escape }}
{% endfor %}
<label class="mt-1"> {{ login_form.username.label }} </label>
{{ login_form.username }}
<label class="mt-1"> {{ login_form.password.label }} </label>
{{ login_form.password }}
....
so, the question is, why does this output with html tag
{{ login_error.username|escape }}
{{ login_error.password|escape }}
but this one output without html tag which is basically the same (?) as the above
{% for error in login_error %}
{{ error|escape }}
{% endfor %}
the expected outcome is the field error without html tag, but {{ login_error.username|escape }} also outputs the html tag
{% for error in login_error %}
{{ error|escape }}
{% endfor %}
outputs with no html tag but a loop is needed, i need to output errors individually but without the html tag