Search code examples
pythonflasksession

Flask session dictionary key changing behavior on using a different key


I am trying to understand how to store form data in Flask sessions. I've encountered behavior that seems weird to me when appending data to a session dictionary that has already been defined in a previous request.

I define the following view:

@bp.route("/new-form", methods=("GET", "POST"))
def new_form():
    
    if request.method == "POST":
        
        if not "x" in session:
            session["x"] = []
        session["x"].append(json.dumps(request.form))
        
        return session.get("x")

    return render_template("main/new-form.html")

I would expect session["x"] to keep its data and append the new json data from the form with every request. However, only the most recent form appended to session["x"] is ever displayed.

What I really don't understand is that when I add another key to session before appending the form data to session, the form data acts how I would expect, i.e. session["x"] becomes a long list of each form that is submitted until I clear the data from the session:

if request.method == "POST":
    session["idontgetit"] = 1
    ...

Just adding the line session["idontgetit"] = 1 makes session["x"] behave how I expected.

I am using the back button on my browser to test this, I don't know if that would have any unexpected effects. It behaves consistently both ways.


Solution

  • When you modify a mutable object (in your case its list) stored in session directly (e.g., session["x"].append(...)), Flask's session mechanism doesn't detect the change. This happens because Flask only marks the session as "modified" when you explicitly assign a new value to a key in session.

    You validated this yourself by testing it using session["idontgetit"] = 1

    When you assign a value to session["idontgetit"], Flask detects that the session has been modified. This triggers Flask to regenerate the session cookie, which then includes the updated state of session["x"]

    Quick Easy Fix:

    Solution # 1

    To ensure that your changes to session["x"] are saved, you should reassign the modified list back to session["x"] after making changes.

    Do something like this

    @bp.route("/new-form", methods=("GET", "POST"))
    def new_form():
        if request.method == "POST":
            if "x" not in session:
                session["x"] = []
            # Modify the list and reassign it
            x = session["x"]
            x.append(json.dumps(request.form))
            session["x"] = x  # Reassign to mark the session as modified
    
            return jsonify(session["x"])
    
        return render_template("main/new-form.html")
    

    Solution # 2

    Based on your flask and python version adding this line session.modified = True after you append will do the job.