Me disculpo por "hacer" una pregunta a la que ya sé la respuesta, pero esto fue lo suficientemente frustrante que pensé que la respuesta debería registrarse en stackoverflow. Si alguien tiene algo que agregar a mi explicación, otorgaré la "respuesta". No pude encontrar la respuesta buscando basándose en el problema, pero después de buscar según la respuesta encontré que mi "problema" es documented behavior. También resulta another person had this problem.
Resulta que SessionBase es un objeto similar al diccionario que realiza un seguimiento de cuándo se modifican sus claves, y establece manualmente un atributo modified
(también hay un accessed
). Si te metes con los objetos dentro de las esas teclas, sin embargo, SessionBase no tiene forma de saber que los objetos están modificados, y por lo tanto tus cambios podrían no almacenarse en el back-end que estés utilizando. (Estoy usando un back-end de base de datos; supongo que este problema se aplica a todos los back-ends). Este problema podría no aplicarse a los modelos, ya que el backend probablemente almacena una referencia al modelo (y por lo tanto recibiría cambios cuando se cargara). el modelo de la base de datos), pero el problema se aplica a los diccionarios (y quizás a cualquier otro tipo base de python que deba almacenarse por completo en el almacén de sesiones).
El truco es que cada vez que modifique objetos en la sesión el sesión no se dará cuenta, deberá informar a la sesión explícitamente que se modifica:
>>> request.session.modified = True
Espero que esto ayude a alguien.
La forma llegué alrededor de esta era para encapsular cualquier acción pop en la sesión en un método que toma el cuidado de los detalles (este método también acepta un parámetro de vista para que las variables de sesión pueden ser específica de la vista):
def session_pop(request, view, key, *args, **kwargs):
"""
Either returns and removes the value of the key from request.session, or,
if request.session[key] is a list, returns the result of a pop on this
list.
Also, if view is not None, only looks within request.session[view.func_name]
so that I can store view-specific session variables.
"""
# figure out which dictionary we want to operate on.
dicto = {}
if view is None:
dicto = request.session
else:
if request.session.has_key(view.func_name):
dicto = request.session[view.func_name]
if dicto.has_key(key):
# This is redundant if `dicto == request.session`, but rather than
# duplicate the logic to test whether we popped a list underneath
# the root level of the session, (which is also determined by `view`)
# just explicitly set `modified`
# since we certainly modified the session here.
request.session.modified = True
# Return a non-list
if not type(dicto[key]) == type(list()):
return dicto.pop(key)
# pop a list
else:
if len(dicto[key]) > 0:
return dicto[key].pop()
# Parse out a default from the args/kwargs
if len(args) > 0:
default = args[0]
elif kwargs.has_key('default'):
default = kwargs['default']
else:
# If there wasn't one, complain
raise KeyError('Session does not have key "{0}" and no default was provided'.format(key))
return default
No puedo creer que acabo de pasar una hora y media arrancando la depuración antes de encontrar esta pregunta. Gracias por hacer esta pregunta y gracias a todas las respuestas. Me salvaste los nervios y el resto de mi día. –