how to view WTForms validation errors? - python

I am writing some basic tests and have a test failing.
def test_new_user_registration(self):
self.client.get('/user/register')
form = RegistrationForm(
email=u'crow#crow.com',
first_name=u'Alex',
last_name=u'Frazer',
username=u'crow',
password=u'fake_password',
confirm_password=u'fake_password'
)
self.assertTrue(form.validate())
The assertion error is failing on form.validate(), but how can I view what the validation errors are?

Use form.errors:
errors
A dict containing a list of errors for each field. Empty if the form
hasn’t been validated, or there were no errors.

You can print the errors by adding the following: print form.errors.items().

I had the same problem, and couldnt find the answer anywhere. This is a snippet from my index.html
<div class="all">
<div class="form-group">
{{ form.phone.label(id="label1") }}
{% if form.phone.errors %}
{{ form.phone(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.phone.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.phone(class="form-control", placeholder="Enter Your Phone Number", )}}
{% endif %}
</div>
</div>
And in my forms.py
class AddContestant(FlaskForm):
number = StringField('Phone number', validators=[DataRequired(), Length(min=10, max=15, message="Your phone number should be more than 10 digits and less than 15")])

Related

How to display the field "label" in django's builtin password validation errors?

I am using Django's builtin authentication class views and need to customize the error message displayed when password validation fails.
For example, in the builtin PasswordResetView, if I try to change my password to test, the following errors will display in my template:
new_password2
This password is too short. It must contain at least 8 characters.
This password is too common.
I would like to change new_password2 to New Password.
Here is the relevant part of my template for the PasswordResetView:
{% extends 'registration/base.html' %}
{% block card_body %}
<div class="form-group">
<label for="old_password">
Old Password:
{{ form.old_password }}
</label>
</div>
<div class="form-group">
<label for="new_password1">
New Password:
{{ form.new_password1 }}
</label>
</div>
<div class="form-group">
<label for="new_password2">
Confirm Password:
{{ form.new_password2 }}
</label>
</div>
<div class="form-group">
<input type="submit" value="Change" class="btn float-right login_btn">
</div>
{% endblock card_body %}
{% block card_footer %}
{% if form.errors %}
<p class="d-flex justify-content-center links">
{{ form.errors }}
</p>
{% endif %}
{% endblock card_footer %}
Supply some dict to the template that will map form field names to labels you want like:
fields_mapping = {
'old_password': 'Old password',
'new_password1': 'New password',
'new_password2': 'Confirm password'
}
Just manually iterate over errors and use the the mapping dic to convert field names to labels you want:
{% for field_name in form.errors: %}
{{ fields_mapping[field_name] }}:
{% for err_message in form.errors[field_name]: %}
* {{ err_message }}
{% endfor %}
{% endfor %}
Customize HTML/CSS there as you want

Flask button generated with wtforms not triggering POST request

I'm writing a Flask application that works sort of like a blog. I generated the text boxes with wtforms, but whenever I click on the button to save the text, nothing happens. I get no errors.
I've tried adding print statements to my code, and everything is working fine except that Flask is not receiving the POST request. Clicking the button does absolutely nothing.
This is the code for the endpoint. I added a print() statement after if request.method but nothing printed out, so I'm assuming it's not receiving the POST request:
#app.route("/newtext", methods=["GET", "POST"])
#login_required
def newtext():
form = NewPost()
if request.method == "POST" and form.validate():
new_post = Texts(user_id=current_user.id, title=form.title.data, content=form.content.data)
db.session.add(new_post)
db.session.commit()
new_click = UserActions(user_id=current_user.id, action=4)
db.session.add(new_click)
db.session.commit()
last_text = db.session.query(Texts).order_by(Texts.id.desc()).first()
text_id = last_text.id
text_version = TextVersions(content=form.content.data, user_id=current_user.id, text_id=text_id)
db.session.add(text_version)
db.session.commit()
plaintext = BeautifulSoup(form.content.data)
text_summary = Grammar.summary(plaintext.get_text())
return render_template("summary.html", text_id=text_id, text_summary=text_summary)
else:
return render_template("basiceditor.html", form=form)
And this is the html code for the webpage. It renders okay (the GET method clearly works) but the button does nothing:
<div class="container mt-5">
<div class="content-section">
<form method="POST" action="/newtext">
{{ form.hidden_tag() }}
<fieldset class="form-group">
<legend class="border-bottom mb-4">{{ legend }}</legend>
<div class="form-group">
{{ form.title.label(class="form-control-label") }}
{% if form.title.errors %}
{{ form.title(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.title.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.title(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form-group">
{{ form.content.label(class="form-control-label") }}
{% if form.content.errors %}
{{ form.content(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.content.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.content(class="form-control form-control-lg", id="controleditor") }}
{% endif %}
</div>
</fieldset>
<div class="form-group">
{{ form.submit(class="btn btn-success") }}
</div>
</form>
</div>
</div>
The app reports no errors. It should save the text to the database and send the person to the summary.html page, but clicking on the button does nothing. I am completely stumped.

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.

Python Flask WTForms custom validator does not work

I am trying to create a custom URL validator for a form input field but validator does not seem to work. I applied a DataRequired() to the StringField which works fine but the custom validator does not. Here is code:
def validate_domain(form, field):
url_regex = r'''((http|https)\:\/\/)?[a-zA-Z0-9\.\/\?\:#\-_=#]+\.
([a-zA-Z]){2,6}([a-zA-Z0-9\.\&\/\?\:#\-_=#])*'''
regex = re.compile(url_regex)
url = regex.match(field.data).group()
if url:
field.data = 'http://' + urlparse(url).netloc
else:
raise ValidationError('Please enter a valid URL.')
class SubmitDomainForm(Form):
domain = StringField('Domain', validators=[DataRequired(),
validate_domain])
submit = SubmitField('Crawl')
HTML for the same:
{% extends "layout.html" %}
{% block content %}
<div class="content-section">
<form method="POST" action="">
{{ form.hidden_tag() }}
<fieldset class="form-group">
<legend class="border-bottom mb-4">{{ legend }}</legend>
<div class="form-group">
{{ form.domain.label(class="form-control-label") }}
{% if form.domain.errors %}
{{ form.domain(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.domain.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.domain(class="form-control form-control-lg") }}
{% endif %}
</div>
</fieldset>
<div class="form-group">
{{ form.submit(class="btn btn-outline-info") }}
</div>
</form>
{% endblock content %}
Even when I submit a non URL input the form just submits. I am unable to get what seem to going wrong here.
After testing my comment it seems that multi-lining your regex is likely causing you an issue
import re
from urllib.parse import urlparse
data = 'https://google.com/#resource'
url_regex = r'''((http|https)\:\/\/)?[a-zA-Z0-9\.\/\?\:#\-_=#]+\.([a-zA-Z]){2,6}([a-zA-Z0-9\.\&\/\?\:#\-_=#])*'''
regex = re.compile(url_regex)
url = regex.match(data).group()
print('http://' + urlparse(url).netloc)
the above code works for me.

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

Categories

Resources