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>
Related
I am new to Flask and this practice exercise is really throwing me for a loop. I am trying to create a single page on LocalHost:5000. The Flask_Form has a single input dialogue for a name and I want it to export the name to a "names.txt" doc. From there I am looking for a way to authenticate whether a name is already in the "names.txt" doc.
from flask import Flask, render_template, flash
from flask_wtf import FlaskForm
import os
app = Flask(__name__)
# Secret Key
SECRET_KEY = os.urandom(32)
app.config['SECRET_KEY'] = SECRET_KEY
class NameForm(FlaskForm):
name = StringField("Name", validators=[DataRequired()])
name = None
#app.route('/')
def index()
form = NameForm()
render_template('naming.html', name=name)
After this I have a basic html doc
<!-- naming.html -->
{% for message in get_flashed_messages() %}
<div class="alert alert-warning alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert"
aria-label="Close"></button>
</div>
{% endfor %}
{% if name %}
<h1> Hello {{ name }}!</h1>
{% else %}
<h1>List of Users</h1>
<br/>
<form methods="POST">
{{ form.hidden_tag() }}
{{ form.name.label(class="form-label") }}
{{ form.name(class="form-control") }}
<br/>
{{ form.submit(class="btn btn-primary") }}
</form>
<br/><br/>
{% endif %}
Is there any way to perform what I am attempting to do? I have tried some personal research and haven't found anything fruitful.
I am in the process of designing a website for the Latin language. In the website, I have a feature called "Form Practice," where users can either enter a latin word OR choose a random verb, random adjective, random noun, random participle, or a random pronoun. You can see this layout of the feature in the image below:
Form Practice Feature
As you can see from the image, there are many fields that the user can input. I store all of this information in a Flask Form in a python file, as shown below:
from flask import render_template, request, json, Response, redirect, flash, url_for, session
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, HiddenField, RadioField
from wtforms.validators import DataRequired
class FormPracticeForm(FlaskForm):
form_name = HiddenField('Form Name')
LatinWord = StringField("Enter a word:", validators=[DataRequired()], id="LatinWord", render_kw={'onkeypress': 'handle(event)'} )
Macrons = RadioField(
u'Enter your choice:',
choices=[
('Yes', 'Yes'),
('No', 'No')],
validators=[DataRequired()])
AdjectiveRandomButton = SubmitField("Random Adjective")
NounRandomButton = SubmitField("Random Noun")
VerbRandomButton = SubmitField("Random Verb")
ParticipleRandomButton = SubmitField("Random Participle")
PronounRandomButton = SubmitField("Random Pronoun")
NextButton = SubmitField("Next", render_kw={'autofocus': True})
Then, in the actual HTML file, I reference the flask form and also handle potential errors:
{% extends "layout.html" %}
{% block content %}
<div class="container">
<form name="login" action="" method="post" novalidate>
<fieldset class="form-group">
{{ form.hidden_tag() }}
<div class="container">
<br>
<h2> Form Practice </h2> <br>
<div class="alert alert-info" role="alert">
This feature allows you to practice your word forms.
Please enter a word or select a random word. In addition, please specify whether or not you want to use macrons to get started!
<br>
<br>
NOTE: If you haven't learned a particular form yet, feel free to leave it blank - it will not be counted towards your score.
</div>
</div>
<div class="container">
<br>
<b> Use Macrons: </b>
<div class="form-group">
{% for subfield in form.Macrons %}
<div class="form-check">
{{ subfield }}
{{ subfield.label }}
</div>
{% endfor %}
{% for error in form.Macrons.errors %}
<span class="error-message">{{ error }}</span>
{% endfor %}
</div>
</div>
<div class="container">
<br>
<b> Enter a Latin word: <br> </b>
{{ form.LatinWord(size=35) }}
{% for error in form.LatinWord.errors %}
<span class="error-message"> {{ error }} </span>
{% endfor %}
<br>
<br>
<b>OR click one of the buttons to generate a random word</b>
</div>
<div class="row">
<div class="col">
{{ form.VerbRandomButton() }}
</div>
<div class="col">
{{ form.AdjectiveRandomButton() }} <br>
</div>
<div class="col">
{{ form.NounRandomButton() }}
</div>
<div class="col">
{{ form.ParticipleRandomButton() }}
</div>
<div class="col">
{{ form.PronounRandomButton() }}
</div>
</div>
<div class="container">
<br>
<br>
{{ form.NextButton() }}
</div>
<script>
function handle(e){
if(e.keyCode === 13){
e.preventDefault(); // Ensure it is only this code that rusn
}
}
</script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" ></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js"></script>
</fieldset>
</form>
</div>
{% endblock %}
I am not necessarily running into any problems right now, but I am stuck. I want to make it so that when the user clicks on the "Random Noun" button, for example, a multi-select field catered to nouns appears below the button that the user can select. And then if the user wants to change their mind and wants to select a "Random Verb", the multi-select field that was there disappears and a new one appears under the "Random Verb" button and that is specialized to verbs. I am unsure how to do this using FlaskForms. I was considering switching AdjectiveRandomButton, NounRandomButton, VerbRandomButton, ParticipleRandomButton, and PronounRandomButton to a RadioField as a start, but am unsure where to go from there.
Any help would be appreciated, thanks so much!
Well you could try using if/else conditions but that would be very hard to do it and it might get deeply nested as you project grows. I would suggest to switch from flask forms to JavaScript + jQuery. Basically what I do is I set up the front-end using flask-wtf so it would send a SECRET_KEY to validate the request in the back-end when submitting a form and sending it using jQuery ajax call https://api.jquery.com/jQuery.post/. Then using JavaScript you can quite easy manipulate data-flow and it's presentation / appearance as you have all the access to UI document elements.
I have the validator
EqualTo('pass_confirm', message='Passwords Must Match!')
which when the passwords don't match shows an error like this.
How do I stylize the error message to be red? I've already tried changing the message to a <span style="color:red">, but it renders plain text and not the HTML.
Flask provides an error element in your form for you. To be able to use it, include the following on your template:
Generic example:
{{ form.password.label }}<br>
{{ form.password(size=32) }}<br>
{% for error in form.password.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
I'm building a simple flask app. It accepts numbers from a form, calculates a value from these and then gives it back to the user. I am struggling with an error which keeps popping up saying that 'The method is not allowed for the requested URL.' I (think) ive correctly included the get and post methods for this so im not sure why im getting this error. The app has a wsgi.py type set up. Code is below:
In routes.py:
#app.route('/extraplace/advancedcalculator', methods=['GET', 'POST'])
def calculator():
form = Extraplacecalculatorform()
chanceep = 1.555
investmentreturn= 1.555
if request.method == 'POST':
back_odds = form.back_odds.data
ran = form.Number_running.data
chanceep = calculate_chanceep(back_odds, ran)
investmentreturn = (chanceep * form.back_odds.data)
return render_template('completedcalculator.jinja2', chanceep=chanceep, form=form, investmentreturn=investmentreturn)
In completedcalculator.jinja2:
{% block body %}
<h1>Input your information</h1>
<div class="formwrapper">
<h2 class="title">Contact</h2>
<form method="POST" action="/">
<div class="form-back_odds">{{ form.back_odds.label }} {{ form.back_odds(size=20) }}</div>
<div class="form-lay_odds">{{ form.lay_odds.label }} {{ form.lay_odds }}</div>
<div class="form-extraplace_payout">{{ form.extraplace_payout.label }} {{ form.extraplace_payout }}</div>
<div class="form-Number_running">{{ form.Number_running.label }} {{ form.Number_running }}</div>
<div class="submit-button"> {{ form.submit }}</div>
</form>
</div>
<br>
<br>
{% if chanceep == 1.555 %}
<div>
<a class="btn btn-success" role="button">From analysis of over 10,000 horse races in the past 10 years. Our model predicts a {{chanceep}}% chance that the horse will finish in the extraplace meaning that you will have a {{investmentreturn}}% return of investment»</a>
</div>
{% endif %}
{% endblock %}
The idea behind the code is that by declaring the values of chanceep every time the page is accessed, the value of chanceep could be 1.555 if it is a get request, or the new calculated value if it is a post request. Then in the Jinja file, it will only show the bottom button with details of the calculations if the value is not 1.555 (it is currently only showing if it is 1.555 however for simplicity).
I am able to access the page for the first time however I get the error as soon as I try to post. If anyone has any ideas why this might be I would really appreciate it.
ANSWER:
I solved this issue by changing the code within the formwrapper from:
<div class="formwrapper">
<h2 class="title">Contact</h2>
<form method="POST" action="/">
<div class="form-back_odds">{{ form.back_odds.label }} {{ form.back_odds(size=20) }}</div>
to:
<div class="formwrapper">
<form method="POST" enctype="multipart/form-data">
{{ form.csrf_token }}
<div class="form-back_odds">{{ form.back_odds.label }} {{ form.back_odds(size=20) }}</div>
I am using Flask with WTforms. I am also using the WTFRecaptcha plugin in order to use Captcha fields.
Turns out I need to use two forms on the same page. When I assign a captcha field on each form, one of the captchas is not rendered on the .html page. This is because the captcha is ALWAYS created with the same ID:
Captcha and forms declaration on my forms.py file:
from wtforms import PasswordField, StringField, validators, widgets, RadioField
from wtforms.form import Form
from wtfrecaptcha.fields import RecaptchaField
class FirstForm(Form):
"""First Form"""
#Omitting fields here
captcha_1 = RecaptchaField('Captcha', [], public_key='OMITTING_PUBLIC_KEY', private_key='OMITTING_PRIVATE_KEY', secure=True)
class Secondform(Form):
"""Second Form"""
#Omitting fields here
captcha_2 = RecaptchaField('Captcha', [], public_key='OMITTING_PUBLIC_KEY', private_key='OMITTING_PRIVATE_KEY', secure=True)
Route declaration:
#!/usr/bin/env python
from flask import Flask, render_template, request
from flask.ext.assets import Environment
from forms import FirstForm, SecondForm
from flask import request
from flask import jsonify
#app.route('/test')
def test_form():
"""Test."""
form_1 = FirstForm(request.form, captcha_1={'ip_address': request.remote_addr})
form_2 = SecondForm(request.form, captcha_2={'ip_address': request.remote_addr})
if request.method == 'POST' and (form_1.validate() or form_2.validate()) :
return "Instructions have been sent to your e-mail"
return render_template(
'test-form.html',
title='Get Started',
form_1=form_1,
form_2=form_2
)
test-form.html
{% extends "base.html" %}
{% block content %}
<div class="container block-form">
<div class="row first">
<div class="col-xs-12 col-md-7 border-right">
<h1 class="title">{{ title }}</h1>
<p>{{ description }}</p>
<div class="form-area">
<form method="post">
{% for field in form_1 %}
<div class="form-group{% if field.errors %} has-error has-feedback{% endif %}">
<div class="row">
<div class="col-xs-12 col-md-4">
{{ field.label(class="control-label") }}
</div>
<div class="col-xs-12 col-md-8">
{{ field(class="form-control") | safe }}
</div>
</div>
{% if field.errors %}
<span class="glyphicon glyphicon-remove form-control-feedback"></span>
{% endif %}
{% for error in field.errors %}
<p class="help-block text-danger">
<span class="glyphicon glyphicon-remove"></span>
{{ error }}
</p>
{% endfor %}
</div>
{% endfor %}
<br>
<button type="submit" class="btn btn-gradient">Submit</button>
</form>
</div>
</div>
</div>
<div class="row second">
<div class="col-xs-12 col-md-7 border-right">
<h1 class="title">{{ title }}</h1>
<p>{{ description }}</p>
<div class="form-area">
<form method="post">
{% for field in form_2 %}
<div class="form-group{% if field.errors %} has-error has-feedback{% endif %}">
<div class="row">
<div class="col-xs-12 col-md-4">
{{ field.label(class="control-label") }}
</div>
<div class="col-xs-12 col-md-8">
{{ field(class="form-control") | safe }}
</div>
</div>
{% if field.errors %}
<span class="glyphicon glyphicon-remove form-control-feedback"></span>
{% endif %}
{% for error in field.errors %}
<p class="help-block text-danger">
<span class="glyphicon glyphicon-remove"></span>
{{ error }}
</p>
{% endfor %}
</div>
{% endfor %}
<br>
<button type="submit" class="btn btn-gradient">Submit</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
Code rendered for captcha in form_1 (Up to the div element):
<script src="https://www.google.com/recaptcha/api/challenge?k=6LeCJvUSAAAAAAvqwJEueVdV0wyNLPtX6KWSTdXp" type="text/javascript">
//Other code here omitted
<script src="https://www.google.com/recaptcha/api/js/recaptcha.js" type="text/javascript">
//Other code here omitted
<div id="recaptcha_widget_div" class=" recaptcha_nothad_incorrect_sol recaptcha_isnot_showing_audio">
Code rendered for captcha in form_2 (Up to the div element):
<script type="text/javascript" src="https://www.google.com/recaptcha/api/challenge?k=6LeCJvUSAAAAAAvqwJEueVdV0wyNLPtX6KWSTdXp">
<script type="text/javascript" src="https://www.google.com/recaptcha/api/js/recaptcha.js"/>
<div id="recaptcha_widget_div" style="display: none;"/>
<noscript><iframe src="https://www.google.com/recaptcha/api/noscript?k=6LeCJvUSAAAAAAvqwJEueVdV0wyNLPtX6KWSTdXp" height="300" width="500" frameborder="0"></iframe>
<br> <textarea name="recaptcha_challenge_field" rows="3" cols="40"> </textarea> <input type="hidden" name="recaptcha_response_field" value="manual_challenge"></noscript>
RESULT: Only one captcha is shown.
... Therefore if I have two captcha fields (Possible on two different forms), one won't display.
Any solutions/suggestions?
This is well a well documented limitation of Recaptcha
Currently, the Google captcha mechanism offer only one captcha form per page
I would encourage you to rethink the way you are organizing your page. Forms in HTML are simple by design. Most of the tooling built around them assumes that a page does one thing and submits the result to the server in a single form submission.
Disclaimer: I don't really know anything about your code. Proceeding regardless: it smells like your design might be a too clever. What I mean by this is that if you haven't seen it done somewhere else and google's tooling doesn't support it the issue is probably with your approach.
If you need to commit the result of a single stateless transaction then a <form> is appropriate and WTForms is a great tool to generate it. If you need something richer you might consider the following:
Break your forms out into multiple pages. A simple set of hyperlinks can provide an easily navigable hierarchy.
Build your DOM with javascript and submit to a RESTful endpoint(you can even use WTForms for validation by converting the request body into a MultiDict and Recaptcha supports AJAX)
Build your <form> dynamically with javascript and switch the action to correspond to the correct form processor on your server.
This is not possible with reCAPTCHA.
See the related ASP.NET question: Multiple reCAPTCHAs in one ASP.Net page
And for possible workarounds: How do I show multiple recaptchas on a single page?