Messing with the stack in python
One thing I don’t like in django is that there is no from input firld that’s automatically set to the current logged in user (like the auto_now datetimefield). Problem with such a field is that there isn’t always a current user, since you can also manipulate django objects on the command line (which is great!). But given that there sometimes is a user, why not take advantage of that and inspect the request? Problem is that you don’t have access to the current request from everywhere, but it’s somewhere on the call stack. Fortunately, you don’t have to do ASM hacking to access the python callstack, python has a neat little gem called sys._getframe which works real pythonic and doesn’t even run off the stack but raises a ValueError if you try and access a non-existing frame. Don’t forget to del(frame) though, otherwise python (and in the case of mod_python: apache) segfaults.
def get_user():
i=1
user = None
while True:
try:
frame = sys._getframe(i)
except ValueError: # Stack isn't this deep
break
if 'request' in frame.f_locals and
issubclass(type(frame.f_locals['request']) , HttpRequest):
user = frame.f_locals['request'].user
del(frame)
break
del(frame)
i += 1
return user
Sweet! This is something I’ve been looking a long time for.
Thanks bro!
Cheers, iKoen.
I think it’s interesting to note *why* a “del frame” is needed (sidenote: paratheses are not needed, because del is a keyword and not a function in python).
from http://docs.python.org/lib/inspect-stack.html :
Warning: Keeping references to frame objects, as found in the first element of the frame records these functions return, can cause your program to create reference cycles. Once a reference cycle has been created, the lifespan of all objects which can be accessed from the objects which form the cycle can become much longer even if Python’s optional cycle detector is enabled. If such cycles must be created, it is important to ensure they are explicitly broken to avoid the delayed destruction of objects and increased memory consumption which occurs.
Wasn’t Guido van Rossum complaining about this functionality not really being Pythonic at all when he saw usage of it in web.py? :)
I would solve that using a django middleware: http://paste.pocoo.org/
just register the RequestPublisher as middleware and you can use the `get_request()` function of the same module to get the current request object.
Regards,
Armin
That is the hack to end all hacks! I wouldn’t touch it with a 10-foot pole personally, but if it works for you, great. :)
goddamit: http://paste.pocoo.org/show/629/
Pasted the wrong url.
Armin: Thanks!
Adrian: Then please, please, pretty please give us an AutoCurrentUser and AutoCurrentUserAdd fields, maybe with the middlewa Armin wrote :)