I am using flask wtform and i want to show a confirmation popup after pressing the submit button so user can see that their submission is successful.
forms.py:
post = FloatField('', validators=[DataRequired()])
submit = SubmitField('Quote')
.html:
<form action="{{ url_for('product', id=product.id) }}" method="post">
{{ form.csrf_token }}
<h4>
{{ form.post(class='input-text qty', maxlength='9', placeholder='Price') }}
{{ form.submit(class='button primary-btn', id='orderform') }}
</h4>
</form>
.
.
.
.
.
<script>
$(document).ready(function(){
$("orderform").submit(function(){
alert("Submitted");
});
});
</script>
When i press the submit button the value is added to the database but i don't get any confirmation popup.
Flask has a built-in functionality called Flash, it should be able to provide a feedback for your application, you just have to import this on your routes.py:
from flask import flash
Then, also on your routes.py file, when you want to call the message, just call the flash method:
flash("Your submission is successful")
And finally, at your .html, allow the page to receive the flashing messages:
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for msgs in messages %}
<div class="alert alert-info" role="alert">
{{msgs}}
</div>
{% endfor %}
{% endif %}
{% endwith %}
Related
Am trying to add another custom button, and at the same time I want it to trigger certain processes in Django-admin with templates, below is how I have implemented the template :
{% extends 'admin/custominlines/change_form.html' %}
{% load i18n %}
{% block submit_buttons_bottom %}
{{ block.super }}
{% if request.GET.edit %}
<div class="submit-row">
<input type="submit" value="Custom button" name="_transition-states">
</div>
{% endif %}
{% endblock %}
The button does appear however, when I click it , it doesn't show the print I have inserted in the response_change() function in the admin.py, what am I missing here :
def response_change(self, request, obj):
if '_transition-states' in request.POST:
print("am working")
return super().response_change(request, obj)
When I click the button it just routes back to the previous page.
I'm developing a web interface by using flask.
The user log and reach an html page where a file can be upload. This file will be save and parse by an internal program (no relation with my problem)
I use a File Field in a Flask Form:
class MyForm(FlaskForm):
file = FileField("DROP YOUR FILE HERE", validators=[DataRequired()])
submit = SubmitField('Submit')
I call it in my main programm:
#app.route('/upload', methods=['GET', 'POST'])
#login_required
def uploadfile():
form = MyForm()
if form.validate_on_submit():
file = form.file
file.data.save(os.path.join("path/to/", secure_filename("filename")))
flash("File added")
return redirect(url_for('uploadfile'))
return render_template("upload.html",form=form)
and here is the body of my html page:
<form action="{{url_for('uploadfile')}}" method="post" enctype="multipart/form-data" novalidate>
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<p class="error">{{ message }}</p>
{% endfor %}
{% endif %}
{% endwith %}
{{ form.csrf_token }}
{{form.fichier}}
{% for error in form.fichier.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
<p>{{ form.submit() }}</p>
</form>
The problem is uploading and saving a lot of data take lots of time.
So i want to add a progress bar but i don't know how to get the download progress and send it to my html progress bar.
This is why i ask your help. If you have any solution i will take it.
Thanks you
I am running Django 2.2 and have written a simple shopping cart. I wish to validate two fields at the same time in such a way that both cannot be empty at the same time. In my forms.py,
from django import forms
class CartAddProductForm(forms.Form):
cc_handle = forms.CharField(required=False, label='CC Handle', empty_value='')
lc_handle = forms.CharField(required=False, label='LC Handle', empty_value='')
def clean(self):
cleaned_data = super().clean()
if cleaned_data.get('cc_handle') == '' and cleaned_data.get('lc_handle') == '':
print("issue detected")
raise forms.ValidationError('Either cc or lc handle is required.')
return cleaned_data
This is following the official Django docs on cleaning and validating fields that depend on each other. The print() statement above lets me know that the issue has been detected, i.e. both fields are empty. Running the Django server, I see that the issue was indeed detected but no validation error message was displayed on top of the originating page. The originating page is the product page that contains the product and a link to add the product to the shopping cart. Normally the validation error message is displayed at the top of the page.
According to the docs, the validation is done when is_valid() is called. So I put a diagnostic print of my views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.views.decorators.http import require_POST
from shop.models import Product
from .cart import Cart
from .forms import CartAddProductForm
#require_POST
def cart_add(request, product_id):
cart = Cart(request)
product = get_object_or_404(Product, id=product_id)
form = CartAddProductForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
cart.add(product=product,
cc_handle=cd['cc_handle'],
lc_handle=cd['lc_handle'])
else:
print('invalid form')
return redirect('cart:cart_detail')
And indeed the words 'invalid form' popped up. The code then takes me to the shopping cart. Instead, what I want is to be at the product page and show the validation error informing the reader that both fields cannot be empty. Is there a simple way of doing it?
For required=True fields in the forms, if I leave it blank, there will be a message popping up saying that I need to fill it in. So I want to do something similar except the validation requires that both fields cannot be empty.
This is different from this Stackoverflow answer because that is a registration form. You can redirect it to the same form whereas for this case, the CartAddProductForm is embedded in all the products page on the site. If possible, I want the validation to occur at the same stage as the field with required=True option.
The product/detail.html template looks like the following.
{% extends "shop/base.html" %}
{% load static %}
{% block title %}
{{ product.name }}
{% endblock %}
{% block content %}
<div class="product-detail">
<img src="{% if product.image %}{{ product.image.url }}{% else %}{% static "img/no_image.png" %}{% endif %}">
<h1>{{ product.name }}</h1>
<h2>{{ product.category }}</h2>
<p class="price">${{ product.price }}</p>
<form action="{% url "cart:cart_add" product.id %}" method="post">
{{ cart_product_form }}
{% csrf_token %}
<input type="submit" value="Add to cart">
</form>
{{ product.description|linebreaks }}
</div>
{% endblock %}
Adding this line in form template has cleared your issue.
{{ cart_product_form.non_field_errors }}
product/detail.html:
{% extends "shop/base.html" %}
{% load static %}
{% block title %}
{{ product.name }}
{% endblock %}
{% block content %}
<div class="product-detail">
<img src="{% if product.image %}{{ product.image.url }}{% else %}{% static "img/no_image.png" %}{% endif %}">
<h1>{{ product.name }}</h1>
<h2>{{ product.category }}</h2>
<p class="price">${{ product.price }}</p>
<form action="{% url "cart:cart_add" product.id %}" method="post">
{{ cart_product_form }}
{% csrf_token %}
{{ cart_product_form.non_field_errors }} // This line will raise validation errors
<input type="submit" value="Add to cart">
</form>
{{ product.description|linebreaks }}
</div>
{% endblock %}
Doc:(Copied from official documentation)
Note that any errors raised by your Form.clean() override will not be
associated with any field in particular. They go into a special
“field” (called all), which you can access via the
non_field_errors() method if you need to. If you want to attach errors
to a specific field in the form, you need to call add_error().
Your view is inconditionnally redirecting to cart_details so no surprise you don't see the validation errors - you'd have to render the invalid form for this. You should only redirect when the post succeeded.
I have input type url in a form and Im trying to get the list of validation errors in the same page, but I want the form first send the data to the server and then render the error list but when the input type is set to url and I enter some other text It shows a popup and say Enter valid Url
It does it on the client side before sending any data to the server
I can use it with js and preventDefault but how can I overcome this default behavior using Flask
Here is my code
from flask_wtf import Form
from wtforms.fields import StringField
from flask.ext.wtf.html5 import URLField
from wtforms.validators import DataRequired, url
class BookmarkForm(Form):
url = URLField('url', validators = [DataRequired(), url()])
description = StringField('description')
the main py file
#app.route('/add', methods = ['GET', 'POST'])
def add():
form = BookmarkForm()
if form.validate_on_submit():
url = form.url.data
description = form.description.data
store_bookmark(url, description)
flash('stored "{}"'.format(description))
return redirect(url_for('index'))
return render_template('add.html', form = form)
and the template
<form id='addUrl' action='' method='post'
{% if form.url.errors %} class ='error'
{% endif %}>
{{ form.hidden_tag() }}
<p>Please enter your bookmark here</p>
{{ form.url(size = 50) }}
<p>Please enter additional description</p>
{{ form.description(size = 50) }}
<ul>
{% for error in form.url.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
<button type='submit'>Submit</button>
</form>
It depends on the browser support of HTML5 and It causes client-side validation and prevents data to passed to the server. You can overcome that default behavior of the HTML5 URL field by adding the tag novalidate to your form.
Your template will look like this
<form id='addUrl' action='' method='post' novalidate
{% if form.url.errors %} class ='error'
{% endif %}>
{{ form.hidden_tag() }}
<p>Please enter your bookmark here</p>
{{ form.url(size = 50) }}
<p>Please enter additional description</p>
{{ form.description(size = 50) }}
{# <input type='text' name='url' required> #}
<ul>
{% for error in form.url.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
<button type='submit'>Submit</button>
</form>
I understand that flash() takes only string and displays that in the redirected page.
I m trying to send html through flash
message = "<h1>Voila! Platform is ready to used</h1>"
flash(message)
return render_template('output.html')
output.html
<div class="flashes">
{% for message in get_flashed_messages()%}
{{ message }}
{% endfor %}
</div>
But it is displaying as string <h1>Voila! Platform is ready to used</h1> is there any way to overcome this.
Where possible, a secure approach is to wrap your string in a Markup object before passing it to the template:
Python code:
from flask import Markup
message = Markup("<h1>Voila! Platform is ready to used</h1>")
flash(message)
return render_template('output.html')
Jinja2 Template:
<div class="flashes">
{% for message in get_flashed_messages() %}
{{ message }}
{% endfor %}
</div>
Using {{message|safe}} will work, but also opens up the door for an attacker to inject malicious HTML or Javascript into your page, also known an an XSS attack. More info here if you're interested.
Use the safe filter:
<div class="flashes">
{% for message in get_flashed_messages()%}
{{ message|safe }}
{% endfor %}
</div>
For cases where you might want to control the CSS applied depending on the status of message (Success | Error), the following code might be useful:
{% for category, msg in get_flashed_messages(with_categories=true) %}
<div class="alert {{ category }} alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
{{ msg|safe }}
</div>
{% endfor %}
Another way is to call render_template to the external HTML file and passing that to Markup class.
main/routes.py
from flask import render_template, flash, Markup
from . import blueprint
#blueprint.route("/user")
def user():
flash(Markup(render_template("templates/user.html", name="John Doe"))
return render_template("templates/home.html")
templates/user.html
<h1>User: {{ name }}</h1>