[Tutor] Learning Flask and having a problem with forms.
mhysnm1964 at gmail.com
mhysnm1964 at gmail.com
Sun Feb 12 00:03:52 EST 2023
All,
I am having a problem with the Flask module which allows you to create a web
page. The web page I am building is to permit myself to modify a list of
dicts that I have built from a bunch of plot files for books. The plot files
don't have any good structure, so I couldn't find a method of directly
importing the info into a database. Instead I want to show the content in a
web page as a table. Column 1 is the keys and column 2 is the values. Column
3 is a list of actions you can perform. Currently I only have a "change key"
button. When this button is activated, it is meant to show a hidden form.
This is the bit I cannot get to work.
Below is the routes.py view code:
from flask import render_template, flash, redirect, url_for, request
from app import app
import pickle, pdb
with open('..\\book_list_dict.pkl', 'rb') as file:
records = pickle.load(file)
def capitalize_key ():
fields = ['title', 'author', "genre", "description", "series", "narrated
by", "about the author"]
for record in records:
for key in fields:
if key not in record and key.capitalize() not in record:
record[key.capitalize()] = "Unknown"
elif key in record:
record[key.capitalize()] = record.pop(key)
@app.route('/')
@app.route('/index')
def index():
# displays the index.html file and the first dict from the list.
capitalize_key() # caplise keys within the records list which exist to
make them all the same.
page_length = len(records)
record_index = 0
page_no = record_index + 1
book = records[record_index]
return render_template('index.html', book=book, page_no=page_no,
page_length=page_length)
# moving between books (records)
@app.route('/nextPage/<page_no>')
def nextPage(page_no):
# moves to the next list element containing the dict.
page_no = int(page_no)
page_length = len(records)
if page_no <= page_length:
page_no += 1
book = records[page_no - 1]
return render_template('index.html', book=book, page_no=page_no,
page_length=page_length)
@app.route('/prevPage/<page_no>')
def prevPage(page_no):
# moves to the previous list item containing the dict.
page_no = int(page_no)
page_length = len(records)
if page_no > 1:
page_no -= 1
book = records[page_no - 1]
else:
book = records[0]
return render_template('index.html', book=book, page_no=page_no,
page_length=page_length)
@app.route('/update_key/<selected_key>', methods=["GET", "POST"])
def update_key(selected_key):
pdb.set_trace()
# accepts the modified fields for the key and key value. Updates the list of
dicts and saves back out as a variable. Hack for now.
if request.method == "POST":
new_key = request.form["key_field"]
new_value = request.form["value_field"]
for record in records:
if selected_key in record:
record[new_key] = record.pop(selected_key)
record[new_key] = new_value
flash("Key updated successfully!")
break
with open('..\\book_list_dict.pkl', 'wb') as file:
pickle.dump(records, file)
return redirect(url_for("index"))
return render_template("update_key.html", selected_key=selected_key)
@app.route('/cancel', methods=["GET"])
def cancel():
# cancel the action and hide the form again.
return redirect(url_for("index"))
@app.route('/changeKey/<page_no>', methods=["GET"])
def changeKey(page_no):
return redirect(url_for("index"))
Below is the HTML template. Nothing fancy for now.
<html>
<head>
<title>Current book {{ book['filename'] }}</title>
</head>
<body>
<h1>Reviewing Book {{ book['filename'] }}s</h1>
<p>Current page: {{page_no}} total pages: {{ page_length
}}</p>
<table>
<tr>
<th>Key</th>
<th>Value</th>
<th>Actions</th>
</tr>
{% for key, value in book.items() %}
<tr>
<td>{{ key }}</td>
<td>{{ value }}</td>
<td>
{% if key != "filename" and key != "original_content" %}
<form action="{{ url_for('changeKey', page_no=page_no) }}"
method="get">
<input type="submit" value="Change Key">
<input type="hidden" name="selected_key" value="{{ key }}">
</form>
</td>
{% endif %}
</tr>
{% endfor %}
</table>
<br>
{% if selected_key %}
</form>
<form action="{{ url_for('update_key', selected_key=selected_key) }}"
method="post">
{{ form.csrf_token }}
{{ form.key_field.label }} {{ form.key_field }}<br>
{{ form.value_field.label }} {{ form.value_field }}<br>
<input type="submit" value="Update Key">
</form>
<form action="{{ url_for('cancel') }}" method="post">
<input type="submit" value="cancel">
</form>
{% endif %}
<br>
<form action="{{ url_for('nextPage', page_no=page_no) }}"
method="get">
<input type="submit" value="Next Book">
</form>
<form action="{{ url_for('prevPage', page_no=page_no) }}"
method="get">
<input type="submit" value="Previous Book">
</form>
</body>
</html>
If I don't have the "changeKey" function in routes and use the <form
action="{{ url_for('changeKey', page_no=page_no) }}" method="get"> in the
index.html file. The browser throws Invalid usage of method. Otherwise the
first list element is shown again. I cannot get the form to show. My
alternative options are:
* Create a new template file which is called when the changekey button
is pressed. This then shows the key and value. Not sure how to do that yet.
Then have a update and cancel button. Update of course then applies the
changes. The above code should work in that situation with a slight change.
* Have the key and value columns as input fields. In the action column
have an update button which takes the two fields being edited and updates
them. Not 100% sure how to send two variables to the python function. I
suspect it will be similar to what I am trying to do above.
I was looking at using the WTF-flask module (hope I got that right) and use
a form.py with form classes. Not sure how to get the data from the dict
into the forms fields using this approach. Any help here is welcomed. I know
this is some what brief. But I hope I have given you enough info.
Note: the above script does move between the different dicts stored in the
list.
Sean
More information about the Tutor
mailing list