tags:

views:

96

answers:

2

I noticed a strange behaviour today: It seems that, in the following example, the config.CLIENT variable stays persistent accross requests – even if the view gets passed an entirely different client_key, the query that gets the client is only executed once (per many requests), and then the config.CLIENT variable stays assigned.

It does not seem to be a database caching issue.

It happens with mod_python as well as with the test server (the variable is reassigned when the test server is restarted).

What am I missing here?

#views.py
from my_app import config

def get_client(client_key=None):
    if config.CLIENT == None:
        config.CLIENT = get_object_or_404(Client, key__exact=client_key, is_active__exact=True)
    return config.CLIENT

def some_view(request, client_key):
    client = get_client(client_key)
    ...
    return some_response

# config.py
CLIENT = None
+6  A: 

Multiple requests are processed by the same process and global variables like your CLIENT live as long, as process does. You shouldn't rely on global variables, when processing requests - use either local ones, when you need to keep a variable for the time of building response or put data into the database, when something must persist across multiple requests.

If you need to keep some value through the request you can either add it to thread locals (here you should some examples, that adds user info to locals) or simply pass it as a variable into other functions.

gruszczy
I see. I guess I was expecting this "reset" because I'm coming from PHP (duh), where the variable would be destroyed at the end of the request. I'm trying to "cache" the variable in a config module for as long as the request lasts because I need it elsewhere (outside of view.py) – I keep a language flag in the client object and some other code, otherwise view-agnostic, should use that flag if available. What would be a better design? Keeping it in the session? Passing along request?
Sam
I edited ma answer, to explain what you are asking.
gruszczy
Thank you, your answer taught me something important about Python (Django). I was about to implement thread locals when I realized that I had actually made a fundamental mistake and this can be solved much more easily: get_client() is called once at the beginning of the view, and it does not need to cache the client object. Then this object is available to other modules – just what I needed.
Sam
To clarify: def init_client(client_key=None): client = get_object_or_404(Client, key__exact=client_key, is_active__exact=True) config.CLIENT = client return config.CLIENT
Sam
Should this be you new function? If so, there is no difference in `client = get_object...` `config.CLIENT = client` `return config.CLIENT` and `config.CLIENT = get_object...` `return config.CLIENT`
Felix Kling
A: 

OK, just to make it slightly clearer (and in response to the comment by Felix), I'm posting the code that does what I needed. The whole problem arose from a fundamental misunderstanding on my part and I'm sorry for any confusion I might have caused.

import config

# This will be called once per request/view
def init_client(client_key):
    config.CLIENT = get_object_or_404(Client, key__exact=client_key, is_active__exact=True)

# This might be called from other modules that are unaware of requests, views etc 
def get_client():
    return config.CLIENT
Sam