Building an HTML flask web page - input dependent on launch - python

I am building a website with flask on python. I am new to web development.
I built an HTML page, and now I need it's contents - number of buttons on the page for example - to be possibly different and automatic on each launch of app.py (the flask app running the website). Let's say that the number will be random between 1-10, a number generated in the app.py.
Does this mean that I need to change the HTML on every app.py launch, this by using python and editing the text file "index.html"? Is this bad practice and not a good way of achieving the goal? Are there other better methods to launch an input-dependent HTML page?
Thanks!
Code example:
def change_HTML_page(path,num):
# here read the text file in path, which is an HTML file, page description.
# inside in some place add more rows to describe buttons,
# as many as num.
# Add rows like this one <input type="button" id="i_bnutton" value="i" onclick="change_button_appearence(this)" />
# save text file afer the change
num_of_buttons = randint(0, 10)
page_path = r"docs/pages/index.html"
change_HTML_page(page_path, num_of_buttons);
#app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)

Best way is to pass the num_of_buttons inside the html render command and constract all input buttons with a jinja loop inside your html.
Your code should look like below:
FLASK:
#app.route('/')
def index():
num_of_buttons = randint(0, 10)
return render_template('index.html', num_of_buttons=num_of_buttons)
if __name__ == '__main__':
app.run(debug=True)
And inside your HTML:
{% for i in range(0,num_of_buttons) %}
<input type="button" id="{{i}}_bnutton" value="{{i}}" onclick="change_button_appearence(this)" />
{% endfor %}

Related

Flask App | render template and start automatic download afterwards

I created a Flask app, which receives an input file, extracts the content, converts it to another format and returns a compressed file with the converted content.
#app.route('/', methods=['GET', "POST"])
#app.route('/home', methods=['GET', "POST"])
def home():
form = UploadFileForm()
file = form.file.data
if form.validate_on_submit():
file.save(os.path.join(os.path.abspath(os.path.dirname(__file__)), app.config['UPLOAD_FOLDER'], secure_filename(
file.filename)))
# 1. unzip files in directory
unzip(file.filename)
# 2. starts conversion process
conversion_status = converter().failed_files
# 3. compress generated DICOM files into export .zip file
zip_dir("static/results/conversion")
# 4. routes to downloading page with corresponding download action
return redirect(url_for('download'))
return render_template('index.html', form=form)
So far everything works. Currently I'm routing in step 4 to another function, which renders a result page, telling, if the conversion was fine. It also prints the export files and by clicking on them, the can be downloaded.
#app.route('/download')
def download():
return render_template('download.html', files=os.listdir('static/results/export'), status=conversion_status)
#app.route('/download/<filename>')
def download_file(filename):
return send_from_directory('static/results/export', filename)
Because I'm running that app on a azure web app url, I want to change the process into:
Rendering the result page
Downloading the content automatically afterwards, without user input
Like this:
return render_template('download.html', files=os.listdir('static/results/export'), status=conversion_status)
return send_from_directory('static/results/export', filename)
But I do not have any idea how to render two things after each other
It's not feasible to render two things consecutively within one endpoint.
However, there is a possibility to download the file automatically using JavaScript.
To find your current result within the list of files, you can pass the name as a parameter to the endpoint for the results.
return redirect(url_for('download', f=filename))
Within the endpoint, you ask for this parameter and pass it on to the template along with the list of files found. You can use a simple comparison to identify the file and use an attribute to mark the anchor for download as current.
#app.route('/download')
def download():
current = request.args.get('f')
files = os.listdir('static/results/export')
return render_template('download.html', **locals())
<ul>
{% for file in files -%}
<li>
<a
class="{{ ('', 'dwl-current')[current and current == file] }}"
href="{{ url_for('download_file', filename=file) }}"
download
>{{file}}</a></li>
{% endfor -%}
</ul>
If you add the anchor to run the download, it is now possible to click it automatically.
<script type="text/javascript">
(() => {
const elem = document.querySelector('a.dwl-current');
elem && elem.click();
})();
</script>

Python Flask / HTML - what is the proper way of displaying an output after HTML form submission?

I am very new to web-development (first project) and have started playing around in Flask. The other day I made a very simple temperature converter which I was running on my local host. The page had a form input to type a value, two radio buttons with Fahrenheit and Celsius to define the system of the value, then a convert button. Here is a screenshot:
Here is my Flask code ("main.py"):
from flask import Flask, render_template
from flask import request, redirect
import temperature, convert, determine_system
app = Flask(__name__)
#app.route('/')
def html():
return render_template('index.html')
#app.route('/convert', methods = ['POST'])
def convert():
temp = request.form['temperature']
system = request.form['system']
new_temp, destination_system = determine_system.determine_system(temp, system)
return render_template('convert.html', temp=temp, system=system, new_temp=new_temp, destination_system=destination_system)
if __name__ == "__main__":
app.run()
As you can see, the first function called "html()" initially renders the "index.html" file and the function "convert()" is executed upon clicking the "Convert" button. There are a few other functions that I have in other .py files in the directory that convert the number to the new system.
Here is the body of my "index.html" code:
<body>
<div id="banner">
<h1>Temperature Converter</h1>
<p class="lead">Use this tool to convert temperature between measurement systems</p>
</div>
<form action="/convert" method="post" target="dummyframe">
<input type="text" name="temperature"></input>
<input type="radio" name="system" value="Fahrenheit">Fahrenheit</input>
<input type="radio" name="system" value="Celsius">Celsius</input>
<br>
<br>
<input type="submit" value="Convert"></input>
</form>
</body>
</html>
To display the converted temperature on the webpage, I currently have another HTML file called "convert.html" in my templates directory that is an exact copy of the "index.html" file, except it includes the following three lines of code in the body after the :
div id="output"></div>
<p class="output-statement">{{ temp }}° {{ system }} is equal to {{ new_temp }}° {{ destination_system }}</p>
</div>
In my Flask file ("main.py), I instruct the "convert()" function to render the "convert.html" template which includes the output statement in the code above:
return render_template('convert.html', temp=temp, system=system, new_temp=new_temp, destination_system=destination_system)
This then results in the following (notice the new web address):
I suspect that my way of outputting the converted temperature by redirecting to a new HTML file and web address (http://127.0.0.1:5000/convert) is not efficient or even the correct way of showing accomplishing this. What is the proper way to output something like this? Is there something I can add to the "index.html" file that would allow me to get rid of the "convert.html" file completely? If so, what would I change the last line of the "convert()" function in my Flask ("main.py") file to?
Thank you in advance and any links with more information on this concept are very appreciated!
Yes there is a more efficient solution where you do not need the convert.html:
This is what you will want in your main route. (note: I suggest renaming your route function to something like "index" or "temp" other than "html")
#app.route('/', methods=["GET","POST"])
def html():
output = ""
if request.method == "POST":
temp = request.form['temperature']
system = request.form['system']
new_temp, destination_system = determine_system.determine_system(temp, system)
output = f"{ temp}° { system } is equal to { new_temp }° { destination_system }"
return render_template('index.html', output=output)
Make sure to import request. using: from flask import request
and in your index.html you will now have:
<div id="output"></div>
<p class="output-statement">{{output}}</p>
</div>
And make sure to change form action to action="#" or action=""

Get user input via for loop for python script in a Flask application

I am trying to create a very simple one-page Flask application for a python script that I have. The script requires multiple user inputs in a for-loop with the number of loops being user input as well.
Here is the code in my script to make it more clear:
def shared_books():
import requests as re
from bs4 import BeautifulSoup
import time
num_lists = int(input('Enter the number of lists you would like to search:'))
urls = []
page_counts = []
for i in range(num_lists):
urls.append(input(f'Enter the url for list {i + 1}:'))
page_counts.append(int(input(f'Enter the number of pages for list {i + 1}:')))
I want a simple HTML that will ask the user for the number of lists, then the URL and page count for each list as is shown in my function. Then it will run the entire function.
The HTML code I have right now is super simple and I don't want much else outside of the input parts:
<html>
<head>
<title>Goodreads-App</title>
</head>
<body>
<h1>Welcome to my app!</h1>
<<p>This app will allow you to see books that are
shared between multiple lists on goodreads</p>
</body>
</html>
Please let me know how I can set up this application!
Firstly, I suggest you take a look at the Flask docs. You are doing it right in terms of having a view function, but the input() python keyword doesn't work like that in Flask. Instead, you should render an html template which you can then put your form input field into. Here is an example:
from flask import Flask, render_template
#flask initialising stuff, read docs for info
#app.route("/home")
def home():
return render_template("home.html")
Flask runs on your computer's local server "localhost", which is not publicly accessible. It conventionally runs on port 5000, which gives the name "localhost:5000".
When someone visits "localhost:5000/home", flask will look for a file called "home.html" in a pre-designated templates folder – the default is a directory called "templates" which you should put your html files into.
So if this is your "home.html" file:
<html>
<head>
<title>Goodreads-App</title>
</head>
<body>
<h1>Welcome to my app!</h1>
<p>This app will allow you to see books that are
shared between multiple lists on goodreads</p>
</body>
</html>
When you load the page associated with a specific function, it will return a template which is rendered as html. The above should look something like this:
And that is how to start.
Thank you for the answers! I haven't quite solved the previous issue but have approached it from a different angle which is working now! I will potentially post again if I don't solve it.
I am using flask forms to do what I was trying.

How do I return a web page instead of writing a page in one line in FLASK pythonanywhere?

This entire webpage is written in one line. I would like to write a page using 1000 lines instead of one long line. I would like to write some HTML in one file and display the code when I need it.
I am simply trying to print to lines such as
<p>line 1</p>
<p>line 2</p>
NOT <p>line 1</p><p>line 2</p>
from __future__ import print_function
from flask import Flask
number = "7"
app = Flask(__name__)
redirect = "hi"
#app.route('/')
def hello_world():
stuff = "<h2 style='text-align: center'>Welcome to Python Flask Web Server,
your lucky number is: " + number + "!<h2>\n <p style='text-
align:center;'>Steve Wigmore Trained me!</p>\n
<img style='margin: 0 auto; display: block;
'src='cash-me-
outside-promo.jpg'</img>"
return stuff
What you need is template engine such as Jinja2.
from flask import Flask, render_template
app = Flask(__name__)
number = "7"
#app.route('/')
def index():
return render_template('index.html', number=number)
if __name__ == '__main__':
app.run(debug=True)
and then create a folder named templates in the same folder in which this script is present. Create your own template under templates and then render them in your app.
# templates/index.html
<h2 style='text-align: center'>Welcome to Python Flask Web Server, your lucky number is: {{ number }}!<h2>
<p style='text-align:center;'>Steve Wigmore Trained me! Cash me ousside How bou dat?</p>
<img style='margin: 0 auto; display: block;' src='https://www.maxim.com/.image/t_share/MTQ3MzM2ODA3NjExMTE0OTU4/cash-me-outside-promo.jpg'</img>
For more information about templates in Flask, see https://www.tutorialspoint.com/flask/flask_templates.htm
You should definitely use Jinja 2 Templates. Here are official docs.

Python Flask to change text in a HTML file

I'm trying to create a simple program which will replace {{ test }} with 'Hello world' by following a tutorial, however I am stumped and when I open the HTML file - as {{ test }} is shown on the page instead of 'Hello World' which is what should be appearing.
Any help would be appreciated because I am very unsure on what to do to fix this, thanks.
I am unsure if I have even linked the two files, as to my knowledge it was never specified in the video and I have only just noticed that there is no link between the two files.
Python Code:
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def homepage():
return render_template('index.html', test='hello world')
if __name__ == '__main__':
homepage()
else:
print('Please run this file as main, not as module.')
HTML Code:
<!DOCTYPE HTML>
<html>
<head>
</head>
<body>
<p> {{ test }} </p>
</body>
</html>
Flask is a webserver. You are not meant to call the functions with app.route. Replace the last part with:
if __name__ == '__main__':
app.run()
and then visit http://127.0.0.1:5000/ in your browser. The template file is not meant to change.
If for some reason you don't want to run a server but you just want to create HTML files, then use Jinja2, the template engine behind Flask.

Categories