WTForms getting the errors - python

Currently in WTForms to access errors you have to loop through field errors like so:
for error in form.username.errors:
print error
Since I'm building a rest application which uses no form views, I'm forced to check through all form fields in order to find where the error lies.
Is there a way I could do something like:
for fieldName, errorMessage in form.errors:
...do something

The actual form object has an errors attribute that contains the field names and their errors in a dictionary. So you could do:
for fieldName, errorMessages in form.errors.items():
for err in errorMessages:
# do something with your errorMessages for fieldName

A cleaner solution for Flask templates:
Python 3:
{% for field, errors in form.errors.items() %}
<div class="alert alert-error">
{{ form[field].label }}: {{ ', '.join(errors) }}
</div>
{% endfor %}
Python 2:
{% for field, errors in form.errors.iteritems() %}
<div class="alert alert-error">
{{ form[field].label }}: {{ ', '.join(errors) }}
</div>
{% endfor %}

For anyone looking to do this in Flask templates:
{% for field in form.errors %}
{% for error in form.errors[field] %}
<div class="alert alert-error">
<strong>Error!</strong> {{error}}
</div>
{% endfor %}
{% endfor %}

With ModelFormFields in SqlAlchemy when used with WTForms, if you have a nested object inside an object (foreign key relationships), here is how you show the relevant errors for fields properly.
Python side:
def flash_errors(form):
for field, errors in form.errors.items():
if type(form[field]) == ModelFormField:
for error, lines in errors.iteritems():
description = "\n".join(lines)
flash(u"Error in the %s field - %s" % (
#getattr(form, field).label.text + " " + error,
form[field][error].label.text,
description
))
else:
for error, lines in errors.iteritems():
description = "\n".join(lines)
flash(u"Error in the %s field - %s" % (
#getattr(form, field).label.text + " " + error,
form[field].label.text,
description
))
Jinja side:
{% with messages = get_flashed_messages(with_categories=true) %}
{% for message in messages %}
{% if "Error" not in message[1]: %}
<div class="alert alert-info">
<strong>Success! </strong> {{ message[1] }}
</div>
{% endif %}
{% if "Error" in message[1]: %}
<div class="alert alert-warning">
{{ message[1] }}
</div>
{% endif %}
{% endfor %}
{% endwith %}
Hope that helps.

Related

problem with setting & accessing a variable value in django template

I want to set a variable err for errors in the form fields (using django 2.1.3):
{% for field in form %}
{% if field.errors %}
{% with field.errors as err %}{% endwith %}
{% endif %}
{% endfor %}
{% if err %}
<div class="alert alert-danger fade show">
<button type="button" class="close" data-dismiss="alert"
aria-label="Close">
<span aria-hidden="true">ร—</span>
</button>
{{ err }}
</div>
{% endif %}
But, while rendering to html the value of the variable has no output. Though, there are errors, which I've raised using forms.ValidationError.
Also, try this like ...
{% for field in form %}
{% if field.errors %}
<div ... >
...
...
{{ field.errors }}
</div>
{% endif %}
{% endfor %}
In this case, output or the errors are showing, but with multiple <div> elements & n no. of times.
I know that, it can be done by another way in the views.py: using 'django.contrib.messages'. Then sending errors to messages.error(), inside form.is_valid(), then ...
{% if messages %}
{% for message in messages %}
{{ message }}
{% endfor %}
{% endif %}
But, I want to manipulate it from forms.py file. So, how do I do it?
๐Ÿ™„๏ธ๐Ÿ˜•๏ธ๐Ÿค”๏ธ๐Ÿคจ๏ธ
Thanks in advance!!
The scope of a with statement is until the matching endwith. Your endwidth is immediately after the with, so the variable exists for no time at all.
Even if this worked, you only define a single err anyway; if there are multiple errors it would only have the value of the last one, which defeats the whole purpose of what you are trying to do.
You should not use contrib.messages for this. You should use the errors from the form, not from the field.
{% if form.errors %}
<div ... >
...
...
{% for error in form.errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
Note you can further customise the way errors are displayed by defining an ErrorList subclass.

How To Display One form error in Django

I have this in my template and i want only to display username error not all form errors
{% for field in form %}
{% for error in field.errors %}
<div class="row">
<div class="small-12 columns val-error-msg error margin-below">
{{ error }}
</div>
</div>
{% endfor %}
{% endfor %}
You could specify a field error with form.field_name.errors
like:
{% if form.username.errors %}
{{form.username.errors}}
# or
# {{form.username.errors.as_text}}
# this will remove the `<ul></ul>` tag that django generates by default
{% endif %}
Ever field has .errors attached to it as well. But note that each field can contain multiple errors (for example a password can be too short, and contain illegal symbols).
You can access these errors through {{ form.field.errors }}, but you already obtain such elements. In case you want to filter in the template to only show the errors of - for example - the username field, you can do so with an {% if ... %} statement:
{% for field in form %}
{% if field.name == "username" %}
{% for error in field.errors %}
<div class="row">
<div class="small-12 columns val-error-msg error margin-below">
{{ error }}
</div>
</div>
{% endfor %}
{% endif %}
{% endfor %}

Form validation: how to get the actual length of a field shown in errors?

My form in Flask WTF looks like this:
class PublishForm(Form):
tweet = TextAreaField('tweet', [validators.DataRequired(), validators.Length(123, 123)])
When I show the error in template, I don't get the actual length shown. Any idea how to achieve this?
<div class="alert alert-danger">
{% for field in form.errors %}
{% for error in form.errors[field] %}
{{ error }}
{% endfor %}
{% endfor %}
</div>
I ended up fixing it like this:
{% if form.errors %}
<div class="alert alert-danger">
{% set count = form.tweet.data|length %}
{% for field in form.errors %}
{% for error in form.errors[field] %}
{{ error }}
Actual Length: {{ count }}
{% endfor %}
{% endfor %}
</div>
{% endif %}

Render field errors in for loop with Flask-WTF

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 %}

Is there a way to hide the csrf label while looping through form using Flask and Flask-WTForms?

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 %}

Categories

Resources