23.6. Try It! Flask Sessions (Part 2)

Now that we can set and access a Flask session, let’s collect entries from the form and add the items to our list.

Note

In the code blocks below, the generic list_name has been replaced with groceries. Feel free to use a different variable name to better describe the elements in your own list.

23.6.1. Add Form Entries to List

The HTML code for the form is complete. However, there is currently no code in main.py to handle form submissions. Let’s fix that.

Return to main.py, and replace the pass keyword in line 10 with this block of 4 statements:

 7
 8
 9
10
11
12
13
14
15
@app.route('/', methods=['GET', 'POST'])
def index():
   if request.method == 'POST':
      new_item = request.form['new_item']
      current_list = session['groceries']
      current_list.append(new_item)
      session['groceries'] = current_list
   else:
      session['groceries'] = []

Code breakdown:

  1. Line 10: Requests the entry submitted from the web form and assigns the string to new_item.

  2. Line 11: Retrieves the groceries list stored in session and assigns it to current_list.

  3. Line 12: Appends new_item to the end of current_list.

  4. Line 13: Reassigns current_list to the session.

Since groceries is already a key in session, line 13 replaces its old value with the updated list.

Save the changes, then reload the webpage. Try submitting a few new items from the form. You should see each entry appear on the page after you click the Add Item button.

23.6.1.1. Avoid Duplicate Entries

As written, the Python code allows users to add the same item to the list multiple times. While this behavior isn’t wrong, it doesn’t fit with the idea of a grocery list.

Modify your code to prevent repeats from happening.

  1. Add a conditional to check if new_item is already present in current_list. If so, don’t add it again. If not, append it to the list.

  2. To prevent issues with case (e.g. "Apples" vs. "apples"), add a string method to the form request on line 10. .lower(), .upper(), .capitalize(), and .title() all work well.

  3. Your code will look something like this:

    10
    11
    12
    13
    14
    new_item = request.form['new_item'].title()  # Standardize case for form entries.
    current_list = session['groceries']
    if new_item not in current_list:          # Check if new_item is actually new.
       current_list.append(new_item)
    session['groceries'] = current_list       # Update the session value.
    
  4. Save your changes, then test your application.

23.6.1.2. Fix the Logic Error

When the browser sends a GET request to the Flask server, the index() function saves an empty list to the session.

session['groceries'] = []

While this is fine the first time we visit the page, it doesn’t help if we have existing data.

Try It!

In the application tab, click in the address bar and tap Enter. This sends a GET request to the server. Notice that any list items displayed on the page disappear!

If our list already contains data, we want to keep those elements after a GET or POST request.

Before assigning an empty list to the groceries key, we need to check to see if it already exists in session. If groceries is NOT part of the session yet, then we should add it and assign the empty list. If groceries is currently a key in session, then we keep it as-is.

  1. Update the else clause in the index() function as follows:

     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    @app.route('/', methods=['GET', 'POST'])
    def index():
       if request.method == 'POST':
          new_item = request.form['new_item'].title()
          current_list = session['groceries']
          if new_item not in current_list:
             current_list.append(new_item)
          session['groceries'] = current_list
       else:
          if 'groceries' not in session:
             session['groceries'] = []
    
  2. When the browser sends a GET request, the else clause runs.

    1. Line 16 checks if the groceries key does NOT exist in the session object.

    2. If True, then the program creates the groceries key and assigns it an empty list.

    3. If False, the code makes no changes to the existing data.

  3. Test your program by adding a few items to the list. Then try:

    1. Loading the page from the address bar.

    2. Opening the application in a new tab.

    3. Stopping and restarting main.py.

    In each case, the contents of your list should persist.

23.6.2. Delete Session Data

So far, we’ve used the browser tools to remove a session cookie. While this works well for visitors to our website, it’s not an option for us as the programmers. Since session files are stored on a user’s device, they decide how to manage them. Well behaved coders do NOT delete files on someone else’s computer!

While we cannot remove a session file, we can clear some or all of the data stored in it. There two methods we can use to remove data from a session.

  1. To remove ALL key/value pairs from a session, the syntax is:

    session.clear()
    
  2. To remove a single key/value pair from a session, the syntax is:

    session.pop('key', None)
    

    Without the None argument, .pop() throws an error if key does not exist in the session. We could use anything in place of None, like 5 or "Hello, World!". However, None represents an empty value, so it makes sense for a missing key.

    Including None sets it as a default value. If key is missing, then .pop() returns None as its result, and our program keeps running.

23.6.2.1. Remove a Specific Value

Since the session in our demo application stores only one key/value pair, using .clear() and .pop() produce the same result.

What if we want to remove only one item from the stored list instead of the entire collection? For that, we need to do a little more work. Right now, if new_item is NOT part of the list, it gets added to the collection. Otherwise, nothing happens.

Let’s update the conditional on line 12 to either add a new item to the list or delete an existing element.

  1. Add an else clause to delete an entry from the list. If the user submits an item that already exists, it is removed from the collection.

    12
    13
    14
    15
    if new_item not in current_list:
       current_list.append(new_item)
    else:
       current_list.remove(new_item)
    
  2. Test your code by adding then removing several items. Be sure to check that the form submissions are case-insensitive.

When done, your application should behave something like this:

GIF showing the addition and deletion of items from a stored list.

23.6.3. Final Touches (Optional)

Your Flask app now allows you to add and remove items. However, there are a few extra features that will improve the user experience and make your project more polished.

These tasks don’t teach you anything new about sessions, but they do provide a good review of older skills.

  1. Use the .sort() method to alphabetize your list. Experiment with using session['groceries'].sort() vs. current_list.sort(). Is there a difference?

  2. Use CSS to make the page look nice.

  3. After an item is added to the list, display a message for the user. Something like, You just added ___.

  4. Instead of an unordered list, use a checkbox form to display the items. When submitted, any items checked in the form will be removed from the list.

    Checkbox form allowing users to remove multiple items at once.

    This is MUCH easier than having to type in the items you want to remove!

Tip

Checkout the final-code branch of the repository to examine one possible solution for the checkbox form.

Also, the buttons branch in the repo shows one way to retrieve data from a <button> element rather than an input box.