New to Python Flask and trying to work out some ideas I have learned.
I am working with Pycharm but it seems that template variables and template tags (such as {% for %}) are not recognised.
My goal is to pass some data into the HTML file and iterate through a list variable.
Already tried to install different packages such as Django, Jinja2 and more. But no luck.
Code Below:
from flask import Flask, render_template, request
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
app = Flask(__name__)
app.config["SECRET_KEY"] = "Key"
my_list = ["One", "Two", "Three"]
#app.route("/", methods=["GET", "POST"])
def index():
return render_template('index.html', my_list=my_list)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>My List<h1>
{% for items in my_list %}
<li>items</li>
{% endfor % }
</body>
</html>
Also note my import statements. Maybe i missed one?
Hope all clear.
Cheers
Kenny.
You have to use {{ ... }} expression in Jinja to get the variable output.
Change <li>items</li> to <li>{{ items }}</li> in your Jinja for loop.
Related
I am having some trouble applying the code in the WTForms documentation to my use case (see "Dynamic Form Composition" section). My goal is to use a list of strings (list_a, of variable length) as an argument to produce a series of checkbox forms. For example, if list_a = ['one, 'two'], then the output would be a form with two checkboxes labeled "one" and "two". The documentation says to use this:
def my_view():
class F(MyBaseForm):
pass
F.username = StringField('username')
for name in iterate_some_model_dynamically():
setattr(F, name, StringField(name.title()))
form = F(request.POST, ...)
# do view stuff
and in my attempt to appropriate it, I've come up with this:
def wrapper_func(list_a):
class Prefs(FlaskForm):
pass
for ele in list_a:
setattr(Prefs, ele, BooleanField(ele) )
form = Prefs(request.POST, ...)
Can anyone help me clean this up to get it to work? I'm not sure what else goes in the last line, or if a list is even allowed in this context. Any input would be greatly appreciated!
Based on your question it's hard to decide whether you are using WTForms or Flask-WTF. The documentation link points to the former, while your example uses the FlaskForm class, which is part of the latter.
The following minimalistic example is made using WTForms.
Project structure:
your_project_folder
├───forms
│ ├───__init__.py
│ └───dynamic_form.py
├───templates
│ └───main.html
├───venv
│ └───your_virtual_environment_files
└───server.py
dynamic_form.py contains your wrapper function without the form instantiation (it just returns the dynamically created form class):
from wtforms import Form, BooleanField
def wrapper_func(list_a):
class Prefs(Form):
pass
for ele in list_a:
setattr(Prefs, ele, BooleanField(ele))
return Prefs
main.html contains the HTML code with Jinja2 syntax to generate the form:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form method="POST">
{% for field in form %}
<div>{{ field.label }}: {{ field }}</div>
{% endfor %}
<button type="submit">Submit</button>
</form>
</body>
</html>
server.py puts everything together:
from flask.app import Flask
from flask import request, render_template, redirect
from forms.dynamic_form import wrapper_func
app = Flask('form_app')
#app.route('/', methods=['GET', 'POST'])
def main():
input_list = ['one', 'two', 'three'] # generate it as needed
prefs = wrapper_func(input_list)
form = prefs(request.form)
if request.method == 'POST' and form.validate():
# do your logic with the submitted form data here
return redirect('/')
return render_template("main.html", form=form)
if __name__ == '__main__':
app.run(host='localhost', port=3456, debug=True)
The last two lines are strictly for development purpose!
Please let me know if this example helps!
Currently building a Flask app and using wtforms to help with building a file upload field, but I would like users to have the option to view the (multiple) file names they have already uploaded, either add more files, or remove some files that might have been wrongly uploaded, before finally clicking submit and the final list of files are then processed. Would prefer to continue using wtforms but open to any other solutions.
Minimum example: App.py
from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import StringField, MultipleFileField, SubmitField
app = Flask(__name__)
app.config['SECRET_KEY'] = 'example'
class exampleUpload(FlaskForm):
name = StringField('name')
input_files = MultipleFileField('files')
submit = SubmitField('submit')
#app.route('/')
def index():
form = exampleUpload()
if form.validate_on_submit():
# allow user to freely add, remove, make sure that uploaded files are correct before
# pressing the submit button
if form.submit.data:
files = form.input_files.data
# do_something(files)
return '<h1> Done'
return render_template('index.html', form=form)
if __name__ == "__main__":
app.run(debug=True)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ form.name }}
{{ form.input_files }}
<hr>
{{ form.submit }}
</body>
</html>
Ive made a flask script which runs fine however im trying to display some values in a table on another html page which for some reason is not happening.
i've already tried going through jinja2 documentation and a few other answers but it didn't help much.
the flask file.py
from flask import Flask,render_template,request
app = Flask(__name__)
from webscraper import keeda,display_tbl
#app.route('/', methods=['POST', 'GET'])
def scraper():
if request.method == 'POST':
url = request.form['url']
df=keeda(url)
return render_template(('completed.html',display_tbl(df)))
else:
return render_template('index.html')
if __name__ == '__main__':
app.run()
the completed.html file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Summary of Scraped Data</title>
</head>
<body>
<h1>This is what you got! </h1>
<div>
{{ display_tbl(df) }}
</div>
</body>
</html>
here's the error: jinja2.exceptions.UndefinedError: 'display_tbl' is undefined
i wanted to display a table with values on this page.
You are expecting more than what jinja2 can do for you. Please understand jinja2 is just a way to render templates which are eventually html and javascript, nothing fancy. So, in your case you cannot pass a Python function to your jinja2 template and expect that to run fine. What you can do here is to pass the data returned by display_tbl while rendering template like this:
def scraper():
...
return render_template(('completed.html', data=display_tbl(df))) # data= is important because this is how you are going to access your data in the template
…
def display_tbl(df):
… # Here you should be returning the data you want to display - a list or dict
In the template
<html>
<head>
<meta charset="UTF-8">
<title>Summary of Scraped Data</title>
</head>
<body>
<h1>This is what you got! </h1>
<div>
{{ render_data() }}
</div>
<script>
var d = data | tojson
function render_data() {
// implement the logic to handle how your data should be rendered
}
</script>
</body>
</html>
This is just a rough idea but as you can see you need to change the way you are perceiving jinja2 templates and their interaction with Python or Flask backend.
This question already has answers here:
Python Flask Render Text from Variable like render_template
(4 answers)
Closed 3 years ago.
I can not go to about_me page from the index page.
Error :
The requested URL was not found on the server.
and got url like "http://127.0.0.1:5000/%7B%7B%20url_for('about')%20%7D%7D".
from flask import Flask, redirect, url_for
app = Flask(__name__)
#app.route('/')
def index():
return '''
<!DOCTYPE html>
<html lang="en">
<head>
<title>Title</title>
</head>
<body>
<p>welcome home</p>
about
</body>
</html>
'''
#app.route('/about')
def about_me():
return 'about me'
if __name__ == '__main__':
app.run(debug=True)
The formatting you're using to insert the url_for the about me page, namely:
about
Will only work inside of a Jinja template. Those templates get processed by the template engine before the response is returned, and during that processing the notation with the two braces {{ something }} gets recognized and interpreted differently.
Here however, you are not using this notation in a Jinja template, you are using it it in a normal string, a string that does not get processed and thus does not have anything replaced.
The correct way to achieve what you want, in this case would be to parameterize the string and pass the link through formatting. E.g:
#app.route('/')
def index():
return '''
<!DOCTYPE html>
<html lang="en">
<head>
<title>Title</title>
</head>
<body>
<p>welcome home</p>
about
</body>
</html>
'''.format(about_me=url_for('about_me'))
Hope this helps!
In this example:
from flask import Flask, render_template, redirect, session
app = Flask(__name__)
app.secret_key="secret"
#app.route('/')
def landing():
session['results']="<p>Test one</p>"
session['results']+="<p>Test two</p>"
results=session['results']
return render_template('index.html', results=results)
app.run(debug='True')
In my html, I have something like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Game</title>
</head>
<body>
{{ results }}
</body>
</html>
The results are an html page that does not interpret the tags. So, I get a page that looks like this:
<p>Test One</p><p>Test Two</p>
You could escape the HTML:
{{ results|safe}}
or in Python
import jinja2
results = jinja2.escape(results)
The framework is escaping the HTML in the results variable to prevent security holes. Ideally you want to keep the HTML in the template and not be passed in via the variables. The best way to achieve what you want is to iterate over the values in results variable and wrap it in p tags in the template. This can be done like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Game</title>
</head>
<body>
{% for result in results %}
<p>{{ result }}</p>
{% endfor %}
</body>
</html>
The templating language is Jinja2, and you can read about that here: http://jinja.pocoo.org/
Try this:
from flask import Markup
results = Markup(results)