I'm trying to render an html form and pass in a table row with sqlalchemy. So then the form will show up with all it's input fields filled with the row data, with the purpose of editing and sending it back to the db. But somehow the form is displaying only two input fields, both of type text. Integer fields and radio fields are not showing the row's each corresponding value, although the values exist and are not none.
Here's the route:
#app.route('/editar/<string:id>')
def hotel_edit(id):
form = HotelForm()
viaje = arribos.query.get(id)
return render_template('edit_hotel.html', form=form, viaje=viaje)
Here's the html file displaying the wtform object + trying to get the object "viaje" to show the values with no luck:
{% block body %}
<div id="main_form">
<form action="/" method="post" id="ingresos">
{{ form.hidden_tag() }}
<fieldset>
<div class="checks" id="inout">
{{ form.check.label }}
{{ form.check(value=viaje.check) }}
</div>
<div class="horafecha">
{{ form.fecha.label }}
{{ form.fecha(value=viaje.fecha) }}
{{ form.hora.label }}
{{ form.hora(value=viaje.hora) }}
</div>
<div class="textbox">
{{ form.vuelo.label(class="inputtext") }}
{{ form.vuelo(class="inputtext", value=viaje.vuelo) }}
{{ form.habitacion.label(class="inputtext") }}
{{ form.habitacion(class="inputtext", value=viaje.habitacion) }}
{{ form.huespedes.label(class="inputtext") }}
{{ form.huespedes(class="inputtext", value=viaje.huespedes) }}
{{ form.valijas.label(class="inputtext") }}
{{ form.valijas(class="inputtext", value=viaje.valijas) }}
</div>
<div class="checks" id="puerto">
{{ form.puerto.label(class="puertos") }}
{{ form.puerto(class="puertos", value=viaje.puerto) }}
</div>
<div class="buttons">
{{ form.enviar }}
</div>
</fieldset>
</form>
</div>
{% endblock %}
And here's the form (not styled yet):
form
As you can see, most of the input fields are missing the value. Does anyone know how to fix this?
Also: I can show you the form.py file that has the class definition for the entire form, if that helps.
You can populate the form before it's sent to the jinja template from within your route. It would look something like this:
#app.route('/editar/<string:id>')
def hotel_edit(id):
form = HotelForm()
viaje = arribos.query.get(id)
form.check.data = viaje.check
form.fecha.data = viaje.fecha
form.hora.data = viaje.hora
...
return render_template('edit_hotel.html', form=form)
You can then just refer to the form field without passing the value arg.
{% block body %}
<div id="main_form">
<form action="/" method="post" id="ingresos">
{{ form.hidden_tag() }}
<fieldset>
<div class="checks" id="inout">
{{ form.check.label }}
{{ form.check() }}
</div>
<div class="horafecha">
{{ form.fecha.label }}
{{ form.fecha() }}
{{ form.hora.label }}
{{ form.hora() }}
</div>
<div class="textbox">
{{ form.vuelo.label(class="inputtext") }}
{{ form.vuelo(class="inputtext") }}
{{ form.habitacion.label(class="inputtext") }}
{{ form.habitacion(class="inputtext") }}
{{ form.huespedes.label(class="inputtext") }}
{{ form.huespedes(class="inputtext") }}
{{ form.valijas.label(class="inputtext") }}
{{ form.valijas(class="inputtext") }}
</div>
<div class="checks" id="puerto">
{{ form.puerto.label(class="puertos") }}
{{ form.puerto(class="puertos") }}
</div>
<div class="buttons">
{{ form.enviar }}
</div>
</fieldset>
</form>
</div>
{% endblock %}
Related
While "DataRequired" and "NumberRange" produce a pop-up error message, "EqualTo" (and my own custom "MoreThan") do not. How can I get them to also produce a pop-up message?
####################################################################
My form has three fields. "min_nFeatures" has to be lower than "max_nFeatures", so I changed the code of the "EqualTo" validator to "MoreThan" (as advised in Code a validator for a WTForms form which compares the inputs from two fields). The validator is working: if the user enters a larger value for "min_nFeatures", it does not go through (it returns to the same page). However, there is no pop-up message as with the other built-in validators (for example, if the user does not enter anything, there's a pop-up "Please fill out this field"). I would like the same behavior for the custom validator.
My code:
class MoreThan(object):
def __init__(self, fieldname, message=None):
self.fieldname = fieldname
self.message = message
def __call__(self, form, field):
try:
other = form[self.fieldname]
except KeyError:
raise ValidationError(field.gettext("Invalid field name '%s'.") % self.fieldname)
if field.data <= other.data:
d = {
'other_label': hasattr(other, 'label') and other.label.text or self.fieldname,
'other_name': self.fieldname
}
message = self.message
if message is None:
message = field.gettext(
'The maximal number of expressed genes has to be larger than the minimal number of expressed genes')
raise ValidationError(message)
class vln_plot_form(FlaskForm):
min_nFeatures = IntegerField('* Minimal number of expressed genes:', validators=[DataRequired()])
max_nFeatures = IntegerField('* Maximal number of expressed genes:',
validators=[DataRequired(), MoreThan('min_nFeatures')])
max_mtpercent = IntegerField('Maximal percent of mitochondrial gene expression:', validators=[NumberRange(1, 100)])
submit = SubmitField('Submit')
view:
#app.route('/vln', methods=['POST', 'GET'])
def violin_plots():
...
form = vln_plot_form()
if request.method == 'POST':
if form.validate_on_submit():
...
return redirect(url_for('next_page'))
return render_template('violin_plots.html', form=form)
I read Message not flashing on some WTForm validation methods but could not apply it to my case.
########################################################################
edit:
Here's my HTML code:
{% extends 'base.html' %}
{% block head %}
<title>HELLO</title>
{% endblock %}
{% block body %}
<center><h1>Run!</h1></center>
<h2>Step 2/3</h2>
<figure>
<img src={{ vln_plot_file }} align="middle" alt="vln_plot" style="width:70%">
</figure>
<form method="POST" action="" enctype="multipart/form-data">
{{ form.hidden_tag() }}
<div class="form-horizontal">
<div class="form-group col-md-6">
{{ form.csrf_token() }}
<label for=""> {{ form.min_nFeatures.label }}</label>
{{ form.min_nFeatures }}
</div>
<div class="form-group col-md-6">
{{ form.csrf_token() }}
<label for=""> {{ form.max_nFeatures.label }}</label>
{{ form.max_nFeatures }}
</div>
{% if with_mt %}
<div class="form-group col-md-6">
{{ form.csrf_token() }}
<label for=""> {{ form.max_mtpercent.label }}</label>
{{ form.max_mtpercent }}
</div>
{% endif %}
<div class="form-group">
{{ form.csrf_token() }}
{{ form.submit(class="btn btn-primary")}}
</div>
</div>
{% if form.errors %}
{{ form.errors }}
{% endif %}
</form>
{% endblock %}
Since I added "{{ form.errors }}" at the end of the HTML, I do see the correct form.errors at the bottom of the webpage, but this is of course a very ugly way to display the errors...
This should do the trick:
<form method="POST" action="" enctype="multipart/form-data">
{{ form.hidden_tag() }}
<div class="form-horizontal">
<div class="form-group col-md-6">
{{ form.csrf_token() }}
<label for=""> {{ form.min_nFeatures.label }}</label>
{{ form.min_nFeatures }}
{% for error in form.min_nFeatures.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</div>
<div class="form-group col-md-6">
{{ form.csrf_token() }}
<label for=""> {{ form.max_nFeatures.label }}</label>
{{ form.max_nFeatures }}
{% for error in form.max_nFeatures.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</div>
{% if with_mt %}
<div class="form-group col-md-6">
{{ form.csrf_token() }}
<label for=""> {{ form.max_mtpercent.label }}</label>
{{ form.max_mtpercent }}
{% for error in form.max_mtpercent.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</div>
{% endif %}
<div class="form-group">
{{ form.csrf_token() }}
{{ form.submit(class="btn btn-primary")}}
</div>
</div>
</form
Note how I manage the display of errors for each of the fields individually.
I have been working on a website for the past while using flask, python and bootstrap. I added footer to my website and I would like a "contact me" form in the footer. Below is my current code for creating a contact form and displaying this form.
class ContactForm(FlaskForm):
email = StringField("", validators=[DataRequired(), Email()])
content = TextAreaField("", validators=[DataRequired(), length(min=2, max=500)])
submit = SubmitField("Submit")
<form method="POST" action="">
<div class="form-group">
{{ form.email.label(class="form-control-label") }}
{% if form.email.errors %}
{{ form.email(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.email.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.email(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") }}
{% endif %}
</div>
<div class="form-group">
{{ form.submit(class="btn btn-outline-info") }}
</div>
</form>
I created this footer in my "layout.html" file which is the base file that all other html documents extend from so that all pages will have this same footer.
The issue is that then I need to create and instance of this form object on every page of my application and handle the validate_on_submit on every page. (Sample code below)
#app.route("/random_page", methods=["GET", "POST"])
def random_page():
form = ContactForm()
if form.validate_on_submit():
# code to send the email goes here
return render_template("random_page")
I am looking for an easier way to do this so that I don't need to repeat code on every page and so that It can be considerably simpler. I am not very experienced with flask and would highly appreciate the help.
Use the #app.context_processor decorator, documentation to inject an instance of your contact form into the template context for all templates. For example:
#app.context_processor
def inject():
return dict(
contact_form=ContactForm(),
)
Then re-write the form's HTML to use the contact_form template variable, also adding in an appropriate action route.
<form method="POST" action="{{url_for('contact')}}">
<div class="form-group">
{{ contact_form.email.label(class="form-control-label") }}
{% if contact_form.email.errors %}
{{ contact_form.email(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.email.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ contact_form.email(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form-group">
{{ contact_form.content.label(class="form-control-label") }}
{% if contact_form.content.errors %}
{{ contact_form.content(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in contact_form.content.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ contact_form.content(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form-group">
{{ contact_form.submit(class="btn btn-outline-info") }}
</div>
</form>
Then add a route to solely handle this form's postback:
#app.route("/contact", methods=["POST"])
def contact():
form = ContactForm()
if form.validate_on_submit():
# code to send the email goes here
# blah blah
I posted this question earlier but it was then linked to a similar question which don't provide the required solution and was then closed for answering.
So I have created a Flask Application that tracks the movement of products from one location to another while I make movements via the Flask App the form doesn't get validated I tried adding {{ form.hidden_tag() }} and {{ form.csrf_token }} to the html file that takes input from the user.
If I run this application from the terminal on my command line the form is validated and gets added to the database but if I run the flask app and submit the form in the browser it doesn't.
here is my code for the same
class MovementForm(FlaskForm):
to_location = SelectField('To Location', coerce=int)
from_location = SelectField('From Location', coerce=int)
product = SelectField('Product')
quantity = IntegerField('Quantity')
add_movement = SubmitField('Add Movement')
#app.route('/movements',methods=["GET","POST"])
def add_movements():
form = MovementForm()
form.to_location.choices = [(location.id, location.location_name) for location in Location.query.all()]
form.from_location.choices = [(location.id, location.location_name) for location in Location.query.all()]
form.product.choices = [(product.id, product.product_name) for product in Product.query.all()]
form.from_location.choices.insert(0, (0, 'None'))
if form.validate_on_submit():
new_movement = Movement(to_location_id=form.to_location.data, from_location_id=form.from_location.data, product_id=form.product.data, quantity=form.quantity.data)
db.session.add(new_movement)
db.session.commit()
flash('Product has been moved!', 'success')
return redirect(url_for('add_movements'))
return render_template('add_movements.html', form=form)
Here is my html file
<form action="/movements" method="post">
{{ form.hidden_tag() }}
{{ form.csrf_token }}
<div class="row">
<div class="form-group col">
{{ form.from_location.label(class="form-control-label") }}
{{ form.from_location(class="form-control form-control-lg") }}
</div>
<div class="form-group col">
{{ form.to_location.label(class="form-control-label") }}
{{ form.to_location(class="form-control form-control-lg") }}
</div>
</div>
<div class="row">
<div class="form-group col">
{{ form.product.label(class="form-control-label") }}
{{ form.product(class="form-control form-control-lg") }}
</div>
<div class="form-group col">
{{ form.quantity.label(class="form-control-label") }}
{{ form.quantity(class="form-control form-control-lg") }}
</div>
</div>
<div class="form-group">
{{ form.add_movement(class="btn btn-outline-info") }}
</div>
</form>
What's wrong here?
Try to remove to change in the HTML form the form's action.
<form action="" method="post">
{{ form.hidden_tag() }}
{{ form.csrf_token }}
<div class="row">
<div class="form-group col">
{{ form.from_location.label(class="form-control-label") }}
{{ form.from_location(class="form-control form-control-lg") }}
</div>
<div class="form-group col">
{{ form.to_location.label(class="form-control-label") }}
{{ form.to_location(class="form-control form-control-lg") }}
</div>
</div>
<div class="row">
<div class="form-group col">
{{ form.product.label(class="form-control-label") }}
{{ form.product(class="form-control form-control-lg") }}
</div>
<div class="form-group col">
{{ form.quantity.label(class="form-control-label") }}
{{ form.quantity(class="form-control form-control-lg") }}
</div>
</div>
<div class="form-group">
{{ form.add_movement(class="btn btn-outline-info") }}
</div>
</form>
Does this solve the issue?
Also What I suggest you is to add the Flash message into the HTML, because I see that once the Form is submitted it returns back to the 'add_movements' function. Therefore add this:
<div>
{% for msg in get_flashed_messages%}
<h1>{{msg}}</h1>
{% endfor %}
</div>
<form action="" method="post">
{{ form.hidden_tag() }}
{{ form.csrf_token }}
<div class="row">
<div class="form-group col">
{{ form.from_location.label(class="form-control-label") }}
{{ form.from_location(class="form-control form-control-lg") }}
</div>
<div class="form-group col">
{{ form.to_location.label(class="form-control-label") }}
{{ form.to_location(class="form-control form-control-lg") }}
</div>
</div>
<div class="row">
<div class="form-group col">
{{ form.product.label(class="form-control-label") }}
{{ form.product(class="form-control form-control-lg") }}
</div>
<div class="form-group col">
{{ form.quantity.label(class="form-control-label") }}
{{ form.quantity(class="form-control form-control-lg") }}
</div>
</div>
<div class="form-group">
{{ form.add_movement(class="btn btn-outline-info") }}
</div>
#EDIT
I noticed that something is missing in the product field once coerce in missing:
class MovementForm(FlaskForm):
to_location = SelectField('To Location', coerce=int)
from_location = SelectField('From Location', coerce=int)
product = SelectField('Product', coerce=int)
quantity = IntegerField('Quantity')
add_movement = SubmitField('Add Movement')
EDIT #2
In case you run in this kind of issues (which happens all the time) I suggest you to add a print statements and a If/Else clause as well. This will dramatically help you where the issue is ( The issue on your type of problem you posted is that you 'don't see it') and will give you 'eyes.'
For example this is what I would have done:
#app.route('/movements',methods=["GET","POST"])
def add_movements():
form = MovementForm()
form.to_location.choices = [(location.id, location.location_name) for
location in Location.query.all()]
form.from_location.choices = [(location.id, location.location_name)
for location in Location.query.all()]
form.product.choices = [(product.id, product.product_name) for product
in Product.query.all()]
form.from_location.choices.insert(0, (0, 'None'))
if form.validate_on_submit():
print('Form Ok') #if you see the 'Form ok' to see if is validated
new_movement = Movement(to_location_id=form.to_location.data,
from_location_id=form.from_location.data,
product_id=form.product.data, quantity=form.quantity.data)
db.session.add(new_movement)
db.session.commit()
flash('Product has been moved!', 'success')
return redirect(url_for('add_movements'))
else:
print('Form Not Ok') #If you see this printed then you see that
#is not validated
return render_template('add_movements.html', form=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
What is the best way to generate a full styled form using flask and jinja
<div class="form">
{{ form.statement_reference.label() }}
{{ form.statement_reference(value=username) }}
</div>
<div class="form">
{{ form.date.label() }}
{{ form.date() }}
</div>
<div class="form">
{{ form.full_name.label() }}
{{ form.full_name() }}
</div>
<div class="form">
{{ form.address_line_1.label() }}
{{ form.address_line_1() }}
</div>
<div class="form">
{{ form.city.label() }}
{{ form.city() }}
</div>
If I pass them to the template in a list and then iterate over the list, how to I create the label() as well?
something like this;
{% for item in my_list %}
{{ form.{item}.label() }}
{% endfor %}
How would i create these but without having to explicitly stating each one?