I'm trying to complete an assignment that links up Python, Flask, and SQL. I have a database of books with title, author, year, and isbn information. When a search request is carried out a list of applicable results is generated with hyperlinks on each of the titles. I want to create a dynamic url that is dependent on the title that is clicked. The isbn of the clicked book title should be part of the url. However, I don't really know how to achieve this. I've tried the following, but I'm stuck and would appreciate some help.
Here is the application.py
import os
from flask import Flask, redirect, render_template, request, session, url_for
from flask_session import Session
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from helpers import login_required
import requests
app = Flask(__name__)
# Check for environment variable
if not os.getenv("DATABASE_URL"):
raise RuntimeError("DATABASE_URL is not set")
# Configure session to use filesystem
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
# Set up database
engine = create_engine(os.getenv("DATABASE_URL"))
db = scoped_session(sessionmaker(bind=engine))
@app.route("/", methods=["GET", "POST"])
@login_required
def index():
"""Search for books"""
# User reached route via POST (as by submitting a form via POST)
if request.method == "POST":
# Ensure username was submitted
if not request.form.get("search_term"):
return render_template("error.html", message="Enter a book title, author, or ISBN.")
# Search by ISBN, book title or book author
search_term=request.form.get("search_term")
rows = db.execute("SELECT author, title, isbn, year FROM books WHERE (author iLIKE '%"+search_term+"%' OR title iLIKE '%"+search_term+"%' OR isbn iLIKE '%"+search_term+"%')").fetchall()
if not len(rows) >= 1:
return render_template("error.html", message="Sorry, no results match your entry.")
# populate results one dictionary at a time
dict, results = {}, []
for row in rows:
# row.items() returns an array like [(key0, value0), (key1, value1)]
for column, value in row.items():
# join up the dict from the previous iteration (**dict) with the new key-value pair **{column: value}
dict = {**dict, **{column: value}}
results.append(dict)
# Redirect user to results page
return render_template("results.html", results=results)
# User reached route via GET (as by clicking a link or via redirect)
else:
return render_template("index.html")
@app.route("/api/<string:isbn>", methods=["GET"])
@login_required
def books(isbn):
"""Show book details"""
# Make sure book exists
return render_template("book.html")
#TODO
@app.route("/results", methods=["POST"])
def results():
"""Print results to screen"""
return render_template("results.html")
And here is the results.html
{% extends "layout.html" %}
{% block title %}
Results
{% endblock %}
{% block main %}
<script>
book=document.getElementsByClassName(book)
</script>
<table style="margin-left: 5%" class="table table-responsive-sm table-sm table-borderless">
<thead>
<tr align="left">
<th>Author</th>
<th>Title</th>
<th>Year</th>
<th>ISBN</th>
</tr>
</thead>
<tbody>
{% for result in results %}
{% if results != None %}
<tr align="left">
<td>{{ result['author'] }}</td>
<td class="book"><a href="{{url_for('books', result['isbn'])}}" style="color: black;">{{ result['title'] }}</a></td>
<td>{{ result['year'] }}</td>
<td>{{ result['isbn'] }}</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
{% endblock %}
I know the syntax for including the isbn number is incorrect ({{url_for('books', result['isbn']}}) but I thought someone might see more clearly what I'm trying to do if I show everything.