I would like to iterate over form's fields in a template and display fields with errors like this:
{{ form.hidden_tag() }}
{% for field in form if field.widget.input_type != 'hidden' %}
{% if form.errors.field %}
<div class="has-error"> {{ field.label }} {{ field(size=80, class_='form-control') }}</div>
<span style="color: red;">{{ form.errors.field.0 }}</span>
{% else %}
{{ field.label }} {{ field(size=80, class_='form-control') }}
{% endif %}
{% endfor %}
But that doesn't work for some reason- the form renders but the errors are not displayed.
I've already checked solutions here, and here, and also here and none of those have helped.
Could someone please advise how to fix my form to correctly render the errors?
The issue is in using form.errors.field. This would only be accurate in jinja if you had a field named field and not for any other names.
Fortunately, you're already iterating fields, and every field has a .errors property so the shortest solution is to simply use that property
Your code should look something like:
{{ form.hidden_tag() }}
{% for field in form if field.widget.input_type != 'hidden' %}
{% if field.errors %}
<div class="has-error"> {{ field.label }} {{ field(size=80, class_='form-control') }}</div>
<span style="color: red;">{% for error in field.errors %}{{ error }}{% if not loop.last %}<br />{% endif %}{% endfor %}</span>
{% else %}
{{ field.label }} {{ field(size=80, class_='form-control') }}
{% endif %}
{% endfor %}
Related
Im trying to raise error for empty fields or fields which are not validating in form
so Im doing this method below but I know this is not the best way...
views.py :
'KnowledgeForm': form,
'errors': str(form.errors),
but then in Django-template I have to use if for each field and im adding custom name for each field , i dont know why i cant use Verbose_name...
Template :
{% if errors %}
<div class="alert alert-danger">
<p>
{% if KnowledgeForm.errors.KnowledgeTitle %}
عنوان دانش: {{ KnowledgeForm.errors.KnowledgeTitle }}
{% endif %}
{% if KnowledgeForm.errors.KnowledgeTextSummary %}
Summary: {{ KnowledgeForm.errors.KnowledgeTextSummary }}
{% endif %}
{% if KnowledgeForm.errors.KnowledgeFromDate %}
from Date: {{ KnowledgeForm.errors.KnowledgeFromDate }}
{% endif %}
{% if KnowledgeForm.errors.KnowledgetoDate %}
To date : {{ KnowledgeForm.errors.KnowledgetoDate }}
{% endif %}
{% if KnowledgeForm.errors.KnowledgeProcess %}
Chart: {{ KnowledgeForm.errors.KnowledgeProcess }}
{% endif %}
{% endif %}
</p>
</div>
{% endif %}
Second method :
{% if KnowledgeForm.errors %}
<ul class="alert alert-danger">
{% for key,value in KnowledgeForm.errors.items %}
<li>{{ key|escape }} : {{ value|escape }}</li>
{% endfor %}
</ul>
{% endif %}
in this method i get the name based on whats used in models.py how can i change it?
The most clear and concise way is to use a forloop
Try replacing your entire if block in your HTML with the below code
{% for field in KnowledgeForm %}
{% if field.errors %}
<div class="alert alert-danger">
{{ field.label_tag }} {{ field.errors }}
</div>
{% endf %}
{% endfor %}
I don't think you need 'errors': str(form.errors),
It is because you convert errors to str and you don't need to separate this.
In your template:
# if you want to use verbose_name just use label_tag.
# label_tag is equal to your verbose name.
{% for field in KnowledgeForm %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
So you have the error top of input
How can I style my Flask-security login site with Bootstrap? The html form looks like this:
<form action="{{ url_for_security('login') }}" method="POST" name="login_form">
{{ login_user_form.hidden_tag() }}
{{ render_field_with_errors(login_user_form.email) }}
{{ render_field_with_errors(login_user_form.password) }}
{{ render_field_with_errors(login_user_form.remember) }}
{{ render_field(login_user_form.next) }}
{{ render_field(login_user_form.submit) }}
</form>
Bootstrap is implemented, but I dont know how to edit the fields and the submit button..
The render_field_* functions accepts a class_ parameter, which will add HTML classes to the field. Add in bootstrap styling classes as you want.
render_field_with_errors(login_user_form.email, class_="form-control") }}
{{ render_field(login_user_form.submit, class_="btn btn-default") }}
And so on.
Flask-Security uses Flask-WTForms to render and validate forms. In Flask-Security 1.7.5, the default render_field_with_errors and render_field macros defined in "security/_macros.html" are
{% macro render_field_with_errors(field) %}
<p>
{{ field.label }} {{ field(**kwargs)|safe }}
{% if field.errors %}
<ul>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</p>
{% endmacro %}
{% macro render_field(field) %}
<p>{{ field(**kwargs)|safe }}</p>
{% endmacro %}
According to the Flask-WTForms 0.10 docs, both of the above macro functions accept ...
... keyword arguments that are forwarded to WTForm’s field function that renders the field for us. The keyword arguments will be inserted as HTML attributes.
Specifically, the lines {{ field(**kwargs)|safe }} pass the HTML escaped keyword arguments to the field function. Therefore, you can add classes,
{{ render_field_with_errors(login_user_form.email, class="form-control") }}
and can also overwrite default HTML attributes,
{{ render_field_with_errors(login_user_form.email,
class="form-control", type="email", placeholder="Enter email") }}
{{ render_field(login_user_form.submit, class="btn btn-default", value="Submit" ) }}
Additionally, you can define your own macros by modifying the macros above. For example, if you wanted to use Bootstrap alerts to render form validation errors, you could define the macro function render_field_with_bootstrap_errors
{% macro render_field_with_bootstrap_errors(field) %}
<p>
{{ field.label }} {{ field(**kwargs)|safe }}
{% if field.errors %}
{% for error in field.errors %}
<div class="alert alert-danger" role="alert">{{ error }}</div>
{% endfor %}
{% endif %}
</p>
{% endmacro %}
Adding your own macro is pretty simple. For example, you can put custom macros in a "custom_macros.html" file within the templates directory and then load the functions into templates with
{% from "custom_macros.html" import render_field_with_bootstrap_errors %}
This way, it is easy to modify the macros to use different Bootstrap features.
I need to display non_field_errors and field errors in different styles. so i did like below
{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{{ form.non_field_errors }}
</div>
{% endif %}
{% if form.errors %}
<div class="alert alert-info" role="alert">
{% for field in form %}
{% if field.errors %}
{{ field.errors| striptags }}
{% endif %}
{% endfor %}
</div>
{% endif %}
but when there is a non field error without any field errors, both sections are displayed.
How can i display only non field error section if there is no field errors?
Your if condition {% if form.errors %} is triggered when there are form errors, including non field errors.
Maybe you can convert the second block to a for loop and place the if condition within:
{% for field in form %}
{% if field.errors %}
<div class="alert alert-info" role="alert">
{{ field.errors }}
</div>
{% endif %}
{{ field }}
{% endfor %}
This is just a very simple example. You can extend and adapt it according to your needs.
EDIT:
even better solution would be to use django-crispy-forms:
http://django-crispy-forms.readthedocs.org/en/latest/
Don't reinvent the wheel!
EDIT: answer the first comment below
If you really want to display all field errors in a single DIV, for whatever reason you might need that, you could eventually write:
{% if form.errors %}
{# first block #}
{% if form.non_field_errors %}
{# your logic #}
{% endif %}
{# second block #}
<div class="alert alert-info" role="alert">
{% for field in form %}
{{ field.errors }}
{# your logic #}
{% endfor %}
</div>
{% endif %}
So if there are only field errors, the non field errors block won't show up.
I have very simple contact form and I would like to hide the label somehow so that it doesn't show Csrf Token. I am using Flask and Flask-WTForms and am rendering the form like this:
{% for field in form %}
{{ field.label }}
{{ field }}
{% endfor %}
So basically this shows my inputs correctly and the csrf oen is hidden but the label isn't hidden? Should I get over it and implicitly say form.field_name instead of looping through the form or is there a way to handle this "corner case".
I was thinking about doing a logical check in either the for loop declaration or the label declaration but so far I haven't found anything in the documentation that has worked.
Thanks
EDIT: I have "fixed" the problem by doing this but it feels kinda dirty and hacky which I don't like I am still open to a better solution:
{% if not loop.first %}
{{ field.label }}
{% endif %}
If you want a more general solution that works for all hidden fields instead of just the CSRF token:
{{ form.hidden_tag() }}
{% for field in form if field.widget.input_type != 'hidden' %}
{{ field.label }}
{{ field }}
{% endfor %}
form.hidden_tag() is supplied by Flask-WTF.
Just to add to JD's excellent answer...
For those stumbling across this question: You can avoid losing the (csrf) hidden field (and thus protection) by adding the condition "if field.widget.input_type!='hidden' " specifically to the label instead of to the form iterator.
i.e.:
not
{{ form.hidden_tag() }}
{% for field in form if field.widget.input_type != 'hidden' %}
{{ field.label }}
{{ field }}
{% endfor %}
but
{{ form.hidden_tag() }}
{% for field in form %}
{% if field.widget.input_type != 'hidden' %} {{ field.label }} {% endif %}
{{ field }}
{% endfor %}
I think this should work too:
{% for field in form if field.id != 'csrf_token' %}
{{ field.label }}
{{ field }}
{% endfor %}
I have found the way to do it like this:
{% if field.id != 'csrf_token' %}
I believe this to be less hacky. I found this from modifying the example here in the docs.
I made a macro recently to submit forms through ajax in order to not reload the webpage and send it to the api directly.
{% macro render_fields3(form, form_name, method) %}
<form class="ajax" name={{ form_name }} method={{ method }}>
{{ form.hidden_tag() }}
{% for field in form if field.widget.input_type != 'hidden' %}
<dt>{{ field.label }}
<dd>{{field(id=field.name + method)|safe}}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</dd>
{% endfor %}
</form>
{% endmacro %}
I've got a bit of Django form code that looks like this:
class GalleryAdminForm(forms.ModelForm):
auto_id=False
order = forms.CharField(widget=forms.HiddenInput())
And that makes the form field go away, but it leaves the label "Order" in the Django admin page. If I use:
order = forms.CharField(widget=forms.HiddenInput(), label='')
I'm still left with the ":" between where the field and label used to be.
How do I hide the whole thing?!
Oraculum has got it right. You shouldn't be cleaning this up on the client side. If it is clutter, then you shouldn't be sending it to client at all. Building on Oraculum's answer, you should use a custom form template because you you probably still want the hidden values in the form.
{% for field in form.visible_fields %}
<div>
{{ field.errors }}
<span class="filter-label">{{ field.label_tag }}</span><br>
{{ field }}
</div>
{% endfor %}
{% for field in form.hidden_fields %}
<div style="display:none;">{{ field }}</div>
{% endfor %}
Using a custom form template to control hidden fields is cleaner because it doesn't send extraneous info to the client.
I can't believe several people have suggested using jQuery for this...
Is it a case of: when the only tool you know is a hammer everything looks like a nail?
Come on, if you're going to do it from the client-side (instead of fixing the source of the problem in the back-end code) surely the right place to do it would be in CSS?
If you're in the admin site then it's a bit harder but if it's a regular page then it's easy to just omit the whole label from the form template, for example
If you're in the admin site then you could still override the as_table, as_ul, as_p methods of BaseForm (see django/forms/forms.py) in your GalleryAdminForm class to omit the label of any field where the label is blank (or == ':' as the value may be at this stage of rendering)
(...looking at lines 160-170 of forms.py it seems like Django 1.2 should properly omit the ':' if the label is blank so I guess you're on an older version?)
Try
{% for field in form.visible_fields %}
I think it's simpler to achieve the ":" label omission for HiddenInput widget by modifying class AdminField(object) in contrib/admin/helpers.py from :
if self.is_checkbox:
classes.append(u'vCheckboxLabel')
contents = force_unicode(escape(self.field.label))
else:
contents = force_unicode(escape(self.field.label)) + u':'
to :
if self.is_checkbox:
classes.append(u'vCheckboxLabel')
contents = force_unicode(escape(self.field.label))
else:
contents = force_unicode(escape(self.field.label))
#MODIFIED 26/10/2009
if self.field.label <> '':
contents += u':'
# END MODIFY
Check the answer at Create a hidden field in the admin site, it can be done without JavaScript by overriding admin/includes/fieldset.html From there, you can inject a CSS class, and do the rest.
In theory, you should be able to pass label_suffix into the form constructor. However, the Django admin ignores this.
You've been bitten by two bugs in Django: #18134 'BoundField.label_tag should include form.label_suffix' (fixed in trunk, should be in 1.6) and to a lesser extent #11277 Hidden fields in Inlines are displayed as empty rows.
Currently, the best solution is to override the admin fieldset template. Use a HiddenInput for your widget, then override the admin fieldset template (documented here). Just create a templates/admin/includes/fieldset.html with the following contents:
<fieldset class="module aligned {{ fieldset.classes }}">
{% if fieldset.name %}<h2>{{ fieldset.name }}</h2>{% endif %}
{% if fieldset.description %}
<div class="description">{{ fieldset.description|safe }}</div>
{% endif %}
{% for line in fieldset %}
<div class="form-row{% if line.fields|length_is:'1' and line.errors %} errors{% endif %}{% for field in line %}{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% endfor %}">
{% if line.fields|length_is:'1' %}{{ line.errors }}{% endif %}
{% for field in line %}
<div{% if not line.fields|length_is:'1' %} class="field-box{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% if not field.is_readonly and field.errors %} errors{% endif %}"{% endif %}>
{% if not line.fields|length_is:'1' and not field.is_readonly %}{{ field.errors }}{% endif %}
{% if field.is_checkbox %}
{{ field.field }}{{ field.label_tag }}
{% else %}
{# only show the label for visible fields #}
{% if not field.field.is_hidden %}
{{ field.label_tag }}
{% endif %}
{% if field.is_readonly %}
<p>{{ field.contents }}</p>
{% else %}
{{ field.field }}
{% endif %}
{% endif %}
{% if field.field.help_text %}
<p class="help">{{ field.field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
</div>
{% endfor %}
</fieldset>
Based upon the solution by Wilfried Hughes I 've changed the fieldset.html with little improvements.
The code snippet below not only hides the input element instead if the fieldset contains only one single element which input-type is set to hidden it also hides the surrounding div-elements wasting no space in the form.
<fieldset class="module aligned {{ fieldset.classes }}">
{% if fieldset.name %}<h2>{{ fieldset.name }}</h2>{% endif %}
{% if fieldset.description %}
<div class="description">{{ fieldset.description|safe }}</div>
{% endif %}
{% for line in fieldset %}
<div class="form-row{% if line.fields|length_is:'1' and line.errors %} errors{% endif %}{% for field in line %}{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% endfor %}"{% if line.fields|length_is:'1' %}{% for field in line %}{% if field.field.is_hidden %} style="display: none"{% endif %}{% endfor %}{% endif %}>
{% if line.fields|length_is:'1' %}{{ line.errors }}{% endif %}
{% for field in line %}
<div{% if not line.fields|length_is:'1' %} class="field-box{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% if not field.is_readonly and field.errors %} errors{% endif %}"{% endif %}{% if field.field.is_hidden %} style="display: none"{% endif %}>
{% if not line.fields|length_is:'1' and not field.is_readonly %}{{ field.errors }}{% endif %}
{% if field.is_checkbox %}
{{ field.field }}{{ field.label_tag }}
{% else %}
{# only show the label for visible fields #}
{% if not field.field.is_hidden %}
{{ field.label_tag }}
{% endif %}
{% if field.is_readonly %}
<p>{{ field.contents }}</p>
{% else %}
{{ field.field }}
{% endif %}
{% endif %}
{% if field.field.help_text %}
<p class="help">{{ field.field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
</div>
{% endfor %}
The following removes the ':' from all your form fields. I've only tried it with the forms.Form class, but I believe it should work for forms.ModelForm too.
In Django forms, the ':' after the labels is the label_suffix. You can change or remove the label_suffix by creating a subclass of ModelForm, here called UnstyledForm, and redefining the initialization function with label_suffix set to an empty string. Then use your new UnstyledForm class.
class UnstyledForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
kwargs.setdefault('label_suffix', '')
super(UnstyledForm, self).__init__(*args, **kwargs)
class GalleryAdminForm(UnstyledForm):
auto_id=False
order = forms.CharField(widget=forms.HiddenInput())
I hope that helps!
Another way to do it, but i think it still better to iterate form.visible_fields & form.hidden_fields
<form action="{% url 'some_url' param %}" method="POST">
{% csrf_token %}
<div class="row">
{% for field in form %}
{% if not field.is_hidden %}
<div class="col-md-6">
{{ field.label_tag }}
{{ field.error }}
{{ field }}
</div>
{% else %}
{{ field }}
{% endif %}
{% endfor %}
</div>
</form>
If you're using JQuery this should do the trick:
Your form
TO_HIDE_ATTRS = {'class': 'hidden'}
class GalleryAdminForm(forms.ModelForm):
auto_id=False
order = forms.CharField(widget=forms.TextInput(attrs=TO_HIDE_ATTRS))
Javascript code to add to your template
$(document).ready(function(){
$('tr:has(.hidden)').hide();
});
That works if you're rendering your form as a table. If you want to make it work with any kind of form rendering you can do as follows:
$(document).ready(function(){
$('{{ form_field_container }}:has(.hidden)').hide();
});
And add form_field_container to your template context. An example:
If you render your form like this:
<form>
<span>{{ field.label_tag }} {{ field }}</span>
</form>
Your context must include:
'form_field_container': 'span'
You get the idea...