[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