Flask webserver - adding a detail view


Martin McBride, 2020-01-22
Tags template html
Categories flask sqlite

We previously created a page which listed all the fruits in our database. This time we will create another page which displays the details for a particular fruit.

The template

Here is our database table, containing the name, colour and image file name for various fruits:

name color image
Plum Purple plum.jpg
Orange Orange orange.jpg
Banana Yellow banana.jpg
Strawberry Red strawberry.jpg

You should copy the fruit images from github in the folder static to the static subfolder of your working folder.

To show the details of one fruit, we will require a new HTML template, this time we will call it fruit.html. Here is the code:

<html>
  <head>
    <link rel="stylesheet" href='/static/main.css' />
  </head>
  <body>
    <h1>{{name}}</h1>
    <img src="/static/{{image}}"> 
    Name: {{name}}
    Colour: {{color}}
  </body>
</html>

We list the name and colour of the fruit, also using the name as the page title. The image field contains the name of the file containing the fruit image, which we have placed in the static folder along with the css file. To display the image we use an img element:

<img src="static/{{image}}">

The Python code

We also need a new route function, which uses the route /fruit. But the question is, how will the function know which fruit to display?

A common technique, which we will use, is to include the identity of the subject in the URL. So to look at the details for plums we would use /fruit/Plum, for oranges /fruit/Orange, etc.

Here is how we implement this in Flask. We can use the route /fruit/. The function fruit is then passed the value name as a parameter:

@app.route('/fruit/<name>')
def fruit(name):
    con = sqlite3.connect('data.db')
    cur = con.cursor()    
    cur.execute("SELECT * FROM fruits where name = ?", (name,))
    rows = cur.fetchall()
    name = rows[0][0]
    color = rows[0][1]
    image = rows[0][2]

    return render_template('fruit.html', name=name,
                           color=color, image=image)

The rest of the code should be fairly familiar. Notice that the cur.execute() function can take a second parameter - a list (or tuple) of values. These are substituted into the SQL statement wherever there is a ? character so:

    cur.execute("SELECT * FROM fruits where name = ?", (name,))

produces this SQL statement (assuming name has the value "Plum"):

SELECT * FROM fruits where name = Plum

Since each database entry has a unique name, the query will only return one row. cur.fetchall() will return a list with a single entry, a tuple with the values for the selected fruit. For example for Plum rows would contain:

[('Plum', 'Purple', 'plum.jpg')]

Thus the name is rows[0][0], the color is rows[0][1], and the image is rows[0][3].

Updating the fruits page

The fruits page lists all the fruits, but it would be nice if those list items were links to the details page. We can do this quite easily by updating the fruits.html template:

<html>
  <head>
    <link rel="stylesheet" href='/static/main.css' />
  </head>
  <body>
    <h1>{{title}}</h1>
    {% for row in rows %}
      <a href="fruit/{{row[0]}}">{{row[0]}}</a></br>
    {% endfor %}
  </body>
</html>

We just use a link element for each list item:

    <a href="fruit/{{row[0]}}">{{row[0]}}</a></br>

Which becomes (for the plum item) :

    <a href="fruit/Plum"/>Plum</a></br>

The full code for this section and the previous section can be found on github.

If you found this article useful, you might be interested in the book Functional Programming in Python or other books by the same author.

Prev

Popular tags

2d arrays abstract data type alignment and angle animation arc array arrays bar chart bar style behavioural pattern bezier curve built-in function callable object chain circle classes clipping close closure cmyk colour combinations comparison operator comprehension context context manager conversion count creational pattern data science data types decorator design pattern device space dictionary drawing duck typing efficiency ellipse else encryption enumerate fill filter font font style for loop function function composition function plot functools game development generativepy tutorial generator geometry gif global variable gradient greyscale higher order function hsl html image image processing imagesurface immutable object in operator index inner function input installing iter iterable iterator itertools join l system lambda function len lerp line line plot line style linear gradient linspace list list comprehension logical operator lru_cache magic method mandelbrot mandelbrot set map marker style matplotlib monad mutability named parameter numeric python numpy object open operator optimisation optional parameter or pandas partial application path pattern permutations pie chart polygon positional parameter print pure function python standard library radial gradient range recipes rectangle recursion reduce regular polygon repeat rgb rotation roundrect scaling scatter plot scipy sector segment sequence setup shape singleton slice slicing sound spirograph sprite square str stream string stroke structural pattern subpath symmetric encryption template text text metrics tinkerbell fractal transform translation transparency triangle truthy value tuple turtle unpacking user space vectorisation webserver website while loop zip