flask is a Python package which can help you to:
It is a lightweight web application framework which is popular, flexible, and easy to get started with.
from flask import Flask
app = Flask(__name__)
Flask class definition, and assigned an instance of it to appThings we don't need to worry about for now, but:
__name__is a special Python variable which determines where Flask should look for files such as templates__main__ will be the value of __name__ if this file is itself being run directly rather than by another file@app.route('/')
/def index():
return 'Hello, World'
index is used for the root URLif __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
__name__ will equal __main__ because we are running the file directly (unimportant for now).run() method of app will serve the page at the given host (required for replit)debug=True means we can see changes in the page without running the code againTry changing the 'Hello, World' text and refreshing the page.
jinja is a Python package which is used for templating. We can use it to:
The syntax used in Jinja templates is similar to Python.
This code snippet is taken from the example we'll see later, showing a part of the template where rows in a template are created based on data in a list of dictionaries:
{% for activity in activities %}
<tr>
<th scope="row">{{ loop.index }}</th>
<td>{{ activity['activity'] }}</td>
<td>{{ activity['price'] }}</td>
</tr>
{% endfor %}
{% ... %} tags (here designating a for loop){{ ... }} tags (here looking up values in a dictionary)Rather than our page function to simply return text, we can use the flask.render_template() function to:
This is a powerful combination which is central to making our web pages dynamic.
By default, Flask will look for templates in the /templates directory next to the application code.
Here's a Flask example which uses Jinja templating, including the code we've just seen:
site_name = 'Bucket List'
activities = []
votes = [0, 0, 0, 0, 0]
for i in range(5):
resp = requests.get('https://www.boredapi.com/api/activity?type=recreational')
activities.append(resp.json())
site_name to a string, which we'll use in our web pagerequests.get() as seen previously to collect data from an APIactivities now has a list of dictionaries containing data for our pagevotes is a list of values which we can subsequently modifyrequest¶flask.request allows us to determine how a web page we've served with Flask was requested
requests package we just used to fetch dataGET and POST requests@app.route('/', methods=['GET', 'POST'])
methods parameter determines which types of request for the given route i.e. URL are allowed; by default this is only GETdef index():
if request.method == 'POST':
choice = int(request.form['choice'])
votes[choice] += 1
POST request, we'll record the input by modifying our votes listGET request, this will be skipped and votes left unmodifiedrender_template()¶return render_template('index.html', site_name=site_name, activities=activities, votes=votes)
render_template() function, giving our template file as the first argument, followed by two keyword arguments containing our data to be used by the template Take a look at base.html:
<title>{{ site_name }}</title>
<body>
{% block content %}
{% endblock %}
</body>
site_name will be used as the title (shown in the browser tab)content in the given location
_The rest of base.html is simply a 'boilerplate' or 'blank canvas' for using the Bootstrap CSS framework:
Take a look at index.html:
{% extends "base.html" %}
{% block content %}
...
{% endblock %}
the {% extends ... %} statement tells Jinja to use base.html as a starting point for this template
... placing what's between the {% block ... %} and {% endblock ...%} tags in the position with the same label (here content)
there could be several such blocks within base.html and index.html, using different labels
{% for activity in activities %}
<tr>
<th scope="row">{{ loop.index }}</th>
<td>{{ activity['activity'] }}</td>
<td>{{ activity['price'] }}</td>
...
</tr>
{% endfor %}
{% for...%} and {% endfor... %} designate loops to be completed for each item in a listdictionary['key']loop.index returns the current iteration count; note that this isn't zero-indexed, and the first value in the table is 1loop.index0POST requests¶<td>
<form action="." method="POST">
<button type="submit" class="btn btn-outline-primary" value="{{ loop.index0 }}" name="choice">
<span class="badge badge-light">{{ votes[loop.index0] }}</span>
</button>
</form>
</td>
form with a method attribute of POSTaction attributes tells the browser where to send the data, with . meaning 'the current page'name and value attributes of the button match with our logic in the index function