Error message not working as expected in Django - python

I am trying to display a message on order creation success or failure. For messages.success(request, "My message") it is working as expected. But for messages.error(request, "My message") it is not as expected. I read the django messages framework docs, but no use. Can someone tell me why is this happening
Success Message:
Failed Message:
This is supposed to be red alert if I am not wrong.
Here's my html file.
base.html
<main role="main" class="container" >
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
views.py
if verify:
if response_dict['RESPCODE'] == '01':
messages.success(
request, "Thank you for ordering! Your items will be delivered soon")
return redirect(reverse('update-records', kwargs={'order_id': order_id}))
else:
messages.error(
request, "Your order could not be placed, here are the details: " + response_dict['RESPMSG'])
return redirect(reverse('profile-page'))

If the problem is alert-error not working you can use this after have the import statement of your message :
from django.contrib.messages import constants as messages
MESSAGE_TAGS = {
messages.ERROR: 'danger'
}
Reference ->
https://docs.djangoproject.com/en/3.0/ref/contrib/messages/#message-tags

#Sowjanya R Bhat
The method you suggest can be hardcoded but I need to know, why isn't it implementing red alert my default. Your suggestion works however
<main role="main" class="container" >
{% if messages %}
{% for message in messages %}
{% if message.tags == "error"%}
<div class="alert alert-danger">
{{ message }}
</div>
{% else %}
<div class="alert alert-success">
{{ message }}
</div>
{% endif %}
{% endfor %}
{% endif %}

In your HTML:
<script>
setTimeout(function () {
$('#flash').fadeOut('fast');
},5000);
</script>
<div id="flash">
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags}} m-0" role="alert">
<strong>{{ message }}</strong>
</div>
{% endfor %}
{% endif %}
</div>
in django settings.py:
from django.contrib.messages import constants as messages
MESSAGE_TAGS = {
messages.ERROR: 'danger'
}
in django views:
from django.contrib import messages
if verify:
if response_dict['RESPCODE'] == '01':
messages.success(
request, "Thank you for ordering! Your items will be delivered soon")
return redirect(reverse('update-records', kwargs={'order_id': order_id}))
else:
messages.error(
request, "Your order could not be placed, here are the details: " + response_dict['RESPMSG'])
return redirect(reverse('profile-page'))

just use messages.warning instead, it would at least show a color.

This is because alert-error is not a bootstrap class.
The according class is named alert-danger.
Generally the tags line up nicely between bootstrap and django, this is why your code works. But as you see "error" != "danger".
To fix the issue replace
<div class="alert alert-{{ message.tags }}">
{{ message }}
</div>
with
{% if message.tags == "error" %}
<div class="alert alert-danger">
{{ message }}
</div>
{% else %}
<div class="alert alert-{{ message.tags }}">
{{ message }}
</div>
{% endif %}

Related

Media folder not working properly & Images not being saved - Django [duplicate]

In Django forms, it can check whether the form is valid:
if form.is_valid():
return HttpResponseRedirect('/thanks/')
But I'm missing what to do if it isn't valid? How do I return the form with the error messages? I'm not seeing the "else" in any of the examples.
If you render the same view when the form is not valid then in template you can access the form errors using form.errors.
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ 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 %}
An example:
def myView(request):
form = myForm(request.POST or None, request.FILES or None)
if request.method == 'POST':
if form.is_valid():
return HttpResponseRedirect('/thanks/')
return render(request, 'my_template.html', {'form': form})
views.py
from django.contrib import messages
def view_name(request):
if request.method == 'POST':
form = form_class(request.POST)
if form.is_valid():
return HttpResponseRedirect('/thanks'/)
else:
messages.error(request, "Error")
return render(request, 'page.html', {'form':form_class()})
If you want to show the errors of the form other than that not valid just put {{form.as_p}} like what I did below
page.html
<html>
<head>
<script>
{% if messages %}
{% for message in messages %}
alert('{{message}}')
{% endfor %}
{% endif %}
</script>
</head>
<body>
{{form.as_p}}
</body>
</html>
UPDATE:
Added a more detailed description of the formset errors.
Form.errors combines all field and non_field_errors. Therefore you can simplify the html to this:
template
{% load form_tags %}
{% if form.errors %}
<div class="alert alert-danger alert-dismissible col-12 mx-1" role="alert">
<div id="form_errors">
{% for key, value in form.errors.items %}
<span class="fieldWrapper">
{{ key }}:{{ value }}
</span>
{% endfor %}
</div>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
{% endif %}
If you want to generalise it you can create a list_errors.html which you include in every form template. It handles form and formset errors:
{% if form.errors %}
<div class="alert alert-danger alert-dismissible col-12 mx-1" role="alert">
<div id="form_errors">
{% for key, value in form.errors.items %}
<span class="fieldWrapper">
{{ key }}:{{ value }}
</span>
{% endfor %}
</div>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
{% elif formset.total_error_count %}
<div class="alert alert-danger alert-dismissible col-12 mx-1" role="alert">
<div id="form_errors">
{% if formset.non_form_errors %}
{{ formset.non_form_errors }}
{% endif %}
{% for form in formset.forms %}
{% if form.errors %}
Form number {{ forloop.counter }}:
<ul class="errorlist">
{% for key, error in form.errors.items %}
<li>{{form.fields|get_label:key}}
<ul class="errorlist">
<li>{{error}}</li>
</ul>
</li>
{% endfor %}
</ul>
{% endif %}
{% endfor %}
</div>
</div>
{% endif %}
form_tags.py
from django import template
register = template.Library()
def get_label(a_dict, key):
return getattr(a_dict.get(key), 'label', 'No label')
register.filter("get_label", get_label)
One caveat: In contrast to forms Formset.errors does not include non_field_errors.
def some_view(request):
if request.method == 'POST':
form = SomeForm(request.POST)
if form.is_valid():
return HttpResponseRedirect('/thanks'/)
else:
form = SomeForm()
return render(request, 'some_form.html', {'form': form})
This answer is correct but has a problem: fields not defined.
If you have more then one field, you can not recognize which one has error.
with this change you can display field name:
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ field.label }}</strong><span>{{ 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 %}
#AamirAdnan's answer missing field.label; the other way to show the errors in few lines.
{% if form.errors %}
<!-- Error messaging -->
<div id="errors">
<div class="inner">
<p>There were some errors in the information you entered. Please correct the following:</p>
<ul>
{% for field in form %}
{% if field.errors %}<li>{{ field.label }}: {{ field.errors|striptags }}</li>{% endif %}
{% endfor %}
</ul>
</div>
</div>
<!-- /Error messaging -->
{% endif %}
simply you can do like this because when you initialized the form in contains form data and invalid data as well:
def some_func(request):
form = MyForm(request.POST)
if form.is_valid():
//other stuff
return render(request,template_name,{'form':form})
if will raise the error in the template if have any but the form data will still remain as :
error_demo_here
You can put simply a flag variable, in this case is_successed.
def preorder_view(request, pk, template_name='preorders/preorder_form.html'):
is_successed=0
formset = PreorderHasProductsForm(request.POST)
client= get_object_or_404(Client, pk=pk)
if request.method=='POST':
#populate the form with data from the request
# formset = PreorderHasProductsForm(request.POST)
if formset.is_valid():
is_successed=1
preorder_date=formset.cleaned_data['preorder_date']
product=formset.cleaned_data['preorder_has_products']
return render(request, template_name, {'preorder_date':preorder_date,'product':product,'is_successed':is_successed,'formset':formset})
return render(request, template_name, {'object':client,'formset':formset})
afterwards in your template you can just put the code below
{%if is_successed == 1 %}
<h1>{{preorder_date}}</h1>
<h2> {{product}}</h2>
{%endif %}

WTF form.validate_on_submit() is not working while updating a form

I have designed a form to update a task. The form will get the details of the task into the update form and while submitting that form the form.validate_on_submit does not work and redirects again to the same form with the previous values. Here are my routes and template code. I have used {{ form.csrf_token }}. But similar logic works with the newTask route.
Update Route
#main.route('/update/<int:id>',methods=['POST','GET'])
#login_required
def update(id):
if form.validate_on_submit():
t.task_name = form.task_name.data
t.assignee = form.assignee.data
t.deal_size = form.deal_size.data
t.lead_status = form.lead_status.data
t.stage = form.stage.data
t.priority = form.priority.data
t.submission_date = form.date.data
db.session.add(t)
db.session.commit()
return redirect('/')
form = NewTaskForm()
t = Tasks.query.get_or_404(id)
return render_template("update.html",form = form , t = t)
update.html
<form method="POST" action="/update/{{ t.id }}">
{{ form.csrf_token }}
<div class="form-group">
{{ form.task_name.label }}{{ form.task_name(class='form-control',value = t.task_name ) }}
{% if form.task_name.errors %}
{% for error in form.task_name.errors %}
<div class="alert alert-danger" role="alert">
{{ error }}
</div>
{% endfor %}
{% endif %}
</div>
<div class="form-group">
{{ form.assignee.label }}{{ form.assignee(class='form-control',value = t.assignee) }}
{% if form.assignee.errors %}
{% for error in form.assignee.errors %}
<div class="alert alert-danger" role="alert">
{{ error }}
</div>
{% endfor %}
{% endif %}
</div>
<div class="form-group">
{{ form.deal_size.label }}{{ form.deal_size(class='form-control',value = t.deal_size) }}
{% if form.deal_size.errors %}
{% for error in form.deal_size.errors %}
<div class="alert alert-danger" role="alert">
{{ error }}
</div>
{% endfor %}
{% endif %}
</div>
<div class="form-group">
{{ form.lead_status.label }}{{ form.lead_status(class='form-control',value = t.lead_status) }}
{% if form.lead_status.errors %}
{% for error in form.lead_status.errors %}
<div class="alert alert-danger" role="alert">
{{ error }}
</div>
{% endfor %}
{% endif %}
</div>
<div class="form-check padding-none">
{{ form.stage.label(class='form-check-label') }}{{ form.stage(class='form-check-input customRadio',value = t.stage.data) }}
{% if form.stage.errors %}
{% for error in form.stage.errors %}
<div class="alert alert-danger" role="alert">
{{ error }}
</div>
{% endfor %}
{% endif %}
</div>
<div class="form-group">
{{ form.date.label }}{{ form.date(class='form-control',value = t.submission_date.date()) }}
{% if form.date.errors %}
{% for error in form.date.errors %}
<div class="alert alert-danger" role="alert">
{{ error }}
</div>
{% endfor %}
{% endif %}
</div>
{{ form.submit(class="btn btn-outline-primary btn-block") }}
</form>
newTask route
#main.route('/new-task',methods=['POST','GET'])
#login_required
def newTask():
form = NewTaskForm()
if form.validate_on_submit():
t = Tasks()
t.task_name = form.task_name.data
t.assignee = form.assignee.data
t.deal_size = form.deal_size.data
t.lead_status = form.lead_status.data
t.stage = form.stage.data
t.priority = form.priority.data
t.submission_date = form.date.data
db.session.add(t)
db.session.commit()
return redirect('/')
return render_template("newtask.html",form = form)
If you want to redirect the user to the new form use:
#main.route('/update/<int:id>',methods=['POST','GET'])
#login_required
def update(id):
if form.validate_on_submit():
# do something and then redirect
return redirect(url_for('confirm'))
return render_template("update.html",form = form , t = t)
Probably, you need to create a new function for the 'confirmation site' if you haven't done already.
You can look up the flask documentation if you want to have a better understanding of
url_for :
It accepts the name of the function as its first argument and any number of keyword arguments, each corresponding to a variable part of the URL rule. Unknown variable parts are appended to the URL as query parameters.
Here you can find a good explanation as well:
create-dynamic-urls-in-flask

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.

How to flash success and danger with different messages in flask.

I have a flask application where I want to flash different alert messages depending on an action.
here is my first message, where i check if an email matches my regex pattern:
reciver = str(email)
if not re.match(r"[^#]+#[^#]+\.[^#]+", reciver):
flash("Please enter a valid email address", 'error')
return render_template("about.html")
here is the second message, which is displayed if a message is sent successfully:
flash('Message sent succesfully', 'succes')
return render_template("about.html")
here is my HTML code:
<h1 class="mb-5"> Enter your message, and i will get back to you as soon as possible</h1>
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<div class="alert alert-success">
<li>{{ message }} </li>
</div>
{% endfor %}
{% endif %}
{% endwith %}
{% block body %}{% endblock %}
how can I make an alert-danger for the first message and an alert-success for the second message, is there some sort of conditional that can be used?
You can use the following pattern to specify the category parameter of the flash function.
:param category: the category for the message. The following values
are recommended: 'message' for any kind of message,
'error' for errors, 'info' for information
messages and 'warning' for warnings. However any
kind of string can be used as category.
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert {{ category }}"> {{ message|capitalize }} </div>
{% endfor %}
{% endif %}
{% endwith %}
By putting category in the class attribute, you can associate special colors with some css rules like :
.alert.success {
background-color: green;
}
.alert.error {
background-color: red;
}
flash('Message sent successfully', 'success')
flash("Please enter a valid email address", 'error')
These calls will generate:
<div class="alert success"> Message sent successfully </div>
<div class="alert error"> Please enter a valid email address </div>
Official documentation : http://flask.pocoo.org/docs/1.0/patterns/flashing/#flashing-with-categories
With flask 1.0.2 this similar but slightly different approach worked for me - slightly simpler I think:
flash('This is an error message in red', 'danger')
flash('This is an informational message in blue', 'info')
In Flask HTML template:
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}" role="alert"> {{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
This way I didn't need to define any CSS and just used what was already in the default Flask distribution.

WTForms getting the errors

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.

Categories

Resources