This worksheet focuses on the basics of HTML/CSS and the Python web framework Flask. (We'll continue working on Flask in the upcoming week, with more Flask-related exercises coming in Worksheet 14.)
These things might be helpful while working on the problems. Remember that for worksheets, we don't strictly limit what resources you can consult, so these are only suggestions.
Here is the code for an HTML document that, when loaded in a browser, just displays the word "onions" in the center of the browser window.
<html>
<head>
<title>No title</title>
<style>
/* Adapted from https://stackoverflow.com/questions/982054/
A class that places the object in the center of the
browser window. */
.center-screen {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
min-height: 100vh;
}
</style>
</head>
<body>
<div class="center-screen">
onions
</div>
</body>
</html>
Put this in an HTML file, save it, and confirm you can load it in a browser.
Now, modify it in the following ways.
The HTML above has inline CSS (that is, it is in a <style>
tag). Convert it to use an external stylesheet called ws13.css
. Confirm it still works.
Change the content of the <div>
from onions
to the number 275
. Modify the CSS so that the page has a dark blue background and a pale yellow-white text color, with a sans serif font.
In the HTML, apply a second class to the <div>
called giant
, and modify the CSS so that class has a font size of 64px
.
Also change the title of the page to Big centered 275
.
Here's what the CSS file may look like:
/* Adapted from https://stackoverflow.com/questions/982054/
A class that places the object in the center of the
browser window. */
.center-screen {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
min-height: 100vh;
}
body{
background-color: darkblue;
color: #FFFBA3; /* https://htmlcolorcodes.com/ */
font-family: Arial;
}
.giant{
font-size: 64px;
}
And here's the corresponding HTML file:
<html>
<head>
<title>Big centered 275</title>
<link rel="stylesheet" href="q1-275.css">
</head>
<body>
<div class="center-screen giant">
275
</div>
</body>
</html>
This problem asks you to write a Flask application, but a relatively simple one that can probably be done without HTML templates. You can use templates if you want, but it's also OK to just write functions that return strings and embed the HTML in those strings.
Make a flask application called spu.py
(single page utilities) that has the following routes, all of which produce a page with a single word or number centered in the browser window, styled as in problem 1.
To be clear, we're talking about a single Flask application, and each part of the problem asks you to add another route to it.
/coin/
¶When you visit localhost:5000/coinflip/
(or the corresponding URL with a different port number that Flask selects), you should see either the word HEADS or TAILS centered on the screen in large letters. The word is selected at random, with each having a 50% probability.
/fib/<n>/
¶When you visit localhost:5000/fib/13/
(or the corresponding URL with a different port number that Flask selects), you should see the number 233 centered on the screen in large numerals. More generally, if you replace 13 in the URL with another positive integer $n$, the page should display the $n^{\mathrm{th}}$ Fibonacci number $F_n$ in the same way.
/switch/<x>/
¶When you visit localhost:5000/switch/1/
(or the corresponding URL with a different port number that Flask selects), you see the word ON in the center of the screen in big black letters against a white background. The word ON is actually a link, and if you click it, it takes you to /switch/0/
. That page shows the word OFF in white text on a black background, with OFF being a link to /switch/1/
.
Thus, this part of the app behaves like a light switch. Clicking toggles it on or off.
For simplicity, the solutions in the cells below do not use templates.
To see a version of part A that does use templates, see this link: (Google drive link).
This contains a zip file with the required files arranged as needed (including a .py
file to run the flask application, a .HTML
file for the template, and a corresponding .css
file used by the HTML page). Solutions for questions other than part A using templates are not shown, but the non-template versions can be modified analogously.
import flask
import random
app = flask.Flask("Utilities")
@app.route("/coin/")
def coinflip():
"""Randomly displays "HEADS" or "TAILS" with 50/50 odds"""
word = random.choice(["HEADS", "TAILS"])
return """
<!doctype html>
<html>
<head><title>Coin flip</title></head>
<body style="display:flex; flex-direction:column; justify-content:center; align-items:center; text-align:center; min-height:100vh;">
<p style="font-size:64px;">{}</p>
</body>
</html>
""".format(word)
def fib(n):
"""Recursive function for n-th Fibonacci number"""
if n == 0 or n == 1:
return n
else:
return fib(n-1) + fib(n-2)
@app.route("/fib/<n>/")
def fib_webpage(n):
"""Display n-th Fibonacci number in big numbers in center of screen"""
n = int(n)
return """
<!doctype html>
<html>
<head><title>Fibonacci</title></head>
<body style="display:flex; flex-direction:column; justify-content:center; align-items:center; text-align:center; min-height:100vh;">
<p style="font-size:64px;">{}</p>
</body>
</html>
""".format(fib(n))
@app.route("/switch/<x>/")
def switch(x):
"""Webpage to simulate a light switch"""
if int(x) == 1:
text = "ON"
background_color = "white"
foreground_color = "black"
link_destination = 0
else:
text = "OFF"
background_color = "black"
foreground_color = "white"
link_destination = 1
return """
<!doctype html>
<html>
<head><title>Switch goes wheeeee</title></head>
<body style="background-color:{}; display:flex; flex-direction:column; justify-content:center; align-items:center; text-align:center; min-height:100vh;">
<p>
<a style="color:{}; font-size:64px;" href=/switch/{}/>{}</a>
</p>
</body>
</html>
""".format(background_color, foreground_color, link_destination, text)
app.run()
Here's a SQLite database with information about the first 112 chemical elements:
It has columns:
number
- the atomic numbername
- the element namesymbol
- one- or two-letter symbol for the elementperiodnum
- the number of the period in the periodic table that contains this elementgroupnum
- the number of the group in the periodic table that contains this elementphase
- whether this element is a solid, liquid, or gas at 25C and 1 atmosphere of pressurecategory
- metal, metalloid, noble gas, etc.interesting_fact
- NULL for most, but in some cases contains a sentence with an interesting fact about the element.Make a Flask application that uses HTML templates and this database to generate a page with information about any element on demand.
For example, the endpoint /element/number/4/
should produce a page looking something like this (note the presence of an interesting fact):
The element with atomic number 4. This Alkaline Earth Metal is a solid at standard temperature and pressure. A brittle, toxic metal when pure, it is a component of gemstones such as emerald and aquamarine.
And the endpoint /element/number/61/
should produce a page looking something like this (note the lack of phase information, and the lack of an interesting fact):
The element with atomic number 61. This Lanthanide is an artificially produced element whose phase at standard temperature and pressure is not known.
Add a feature to the application so it also generates the same sort of page at endpoints that specify an element's symbol such as /element/symbol/Ag/
.
import flask
import sqlite3
app = flask.Flask("Elements")
@app.route("/element/number/<n>/")
def element_lookup(n):
"""Webpage with information about element with atomic number `n`."""
con = sqlite3.connect("elements.sqlite")
row = con.execute("SELECT symbol, name, interesting_fact FROM elements WHERE number=?;", [int(n)])
symbol, name, fact = row.fetchone()
if fact is None:
# If a fact is missing, we need to piece one together using other information.
row = con.execute("SELECT number, category, phase FROM elements WHERE number=?;", [int(n)])
number, category, phase = row.fetchone()
fact = "The element with atomic number {}. This {} is ".format(number, category)
if phase == "artificial":
fact += "an artificially produced element whose phase at standard temperature and pressure is not known."
else:
fact += "a {} at standard temperature and pressure.".format(phase)
con.close()
return """
<!doctype html>
<html>
<head><title>Element info</title></head>
<body style="font-family: Arial; padding: 2em; background:#D0D0D0;">
<h1>{}</h1>
<h2>{}</h2>
<p>{}</p>
</body>
</html>
""".format(symbol, name, fact)
@app.route("/element/symbol/<symb>/")
def element_lookup_symbol(symb):
"""Lookup by symbol. Finds the corresponding number then call `element_lookup`."""
con = sqlite3.connect("elements.sqlite")
row = con.execute("SELECT number FROM elements WHERE symbol=?;", [symb])
n = row.fetchone()[0]
con.close()
return element_lookup(n)
app.run()
If you finish the material above, add additional features to the elements Flask app:
Give the element info pages a different background color (always light in color, but maybe green, purple, yellow, or gray) depending on the phase of the element at room temperature (solid, liquid, gas, or artificial/unknown).
Add links to the elements pages that take you to the next and previous element (by atomic number). Hydrogen has no previous element, and Copernicium has no next element in this dataset, so handle those possibilities appropriately.
When asked for an element page, say for element 17, have the application check to see whether a file 117.jpg
exists in the static/
subdirectory. If it does, then have that image included on the page. Add a couple of images of chemical element samples in this way, by finding, downloading, and renaming public-domain images from the web.