0

I notice that variables declared in Python get persisted in memory even in new requests. For example:

from flask import Flask

app = Flask(__name__)

basket = ['apple']

@app.route('/cart/', methods=['POST', 'GET'])
def get_cart():
    return ', '.join(basket)

@app.route('/store/<string:name>')
def add_item(name):
    basket.append(name)
    return 'Added ' + name

app.run(port=5000)

I started it by running python app.py.

At first, the basket list variable only has the item apple. After I tried to add another string "orange" into the basket list, the list now has both apple and orange even when I refresh the /cart/ route. The changes made to the basket list appears to persist even in a new request.

I'd have expected the basket list variable to be "reset" to its original state in a new request because I have done nothing to persist the changes.

If I happen to have a variable which acts as a flag, a previous request will like alter the value of the flag which affects the next request. The requests then become dependent of each other.

How can I make sure that the changes made by somebody in a previous request don't end up affecting another person's separate request?

Carven
  • 14,988
  • 29
  • 118
  • 161
  • 4
    *how can I make sure that the changes made by somebody in a previous request don't end up affecting another person's separate request?* Don't use global variables. – user4815162342 Jul 03 '18 at 16:12
  • 1
    You're going to have to make very significant additions if you want to be able to store each user's basket. – Thomas Jager Jul 03 '18 at 16:12
  • 1
    Also, if you want to scale this web app (for resiliency), then you'd have different in-memory lists for each potential request – OneCricketeer Jul 03 '18 at 16:13

1 Answers1

4

I have done nothing to persist the changes

But you did.

basket is an in-memory data structure that is stored across the Flask Context. Every request will have access to the exact same one. You are not making a basket per-user.

That would require a dict(), or preferably a database (e.g. SQLite) to store a (user, basket) mapping, and you need a way to effectively determine "return customers" to create that user object and differentiate different requests.

Flask does not automatically know two requests were triggered by completely different users.

For example, assuming you have some way to get a user id for a login, then you can do this to get that users cart. For not logged in users, you need some other cookie-like session that you can track for "guest carts", and you need a way to make this unique across users

@app.route('/cart/')
def get_cart():
    b = user_buckets.get(current_user_id())
    return ', '.join(b)

This is not just "how Python works". I'm sure you could write a PHP, Java, NodeJS, whatever web app that stores global state

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
  • If I happen to have a variable which acts as a flag, I probably don't plan to use a database just for a flag. But I wouldn't want a previous request to affect the next request too. In this case, what should I use? – Carven Jul 03 '18 at 16:23
  • Rather than a flag, which is typically considered a boolean, I think you want cookies https://stackoverflow.com/questions/32640090/python-flask-keeping-track-of-user-sessions-how-to-get-session-cookie-id – OneCricketeer Jul 03 '18 at 16:25
  • Also, SQLite on the server side is very cheap. Or use some JavaScript framework on the client side to maintain local client-side storage. – OneCricketeer Jul 03 '18 at 16:27