2010-01-30 16 views
37

sto memorizzazione di dizionari in mia sessione a cui fa riferimento una chiave stringa:Modifica dizionario in Django sessione non modifica Sessione

>>> request.session['my_dict'] = {'a': 1, 'b': 2, 'c': 3} 

Il problema che ho incontrato era che quando ho modificato direttamente il dizionario, il valore non sarebbe cambiato durante la successiva richiesta:

>>> request.session['my_dict'].pop('c') 
3 
>>> request.session.has_key('c') 
False 
# looks okay... 
... 
# Next request 
>>> request.session.has_key('c') 
True 
# what gives! 
+2

Non posso credere di aver appena speso un'ora e mezzo prima di trovare questa domanda. Grazie per aver posto questa domanda e grazie a tutte le risposte. Mi hai salvato i nervi e il resto della mia giornata. –

risposta

32

As thedocumentation states, un'altra opzione è quella di utilizzare

SESSION_SAVE_EVERY_REQUEST=True 

che renderà questo accada ogni richiesta in ogni caso. Potrebbe valerne la pena se questo accade molto nel tuo codice; Sto indovinando l'ulteriore sovraccarico occasionale non sarebbe molto ed è molto meno di quanto i potenziali problemi da trascurare dalla compresa la linea

request.session.modified = True 

ogni volta.

+0

Ho appena notato che questo significa anche che un cookie verrà inviato ogni volta; per i siti con molto traffico suppongo che questo potrebbe rappresentare un problema di larghezza di banda. Inoltre, io non sono molto familiarità con il modo riferimenti lavoro in termini di sessioni, ma cosa succede se hai fatto qualcosa di simile: current_dict = request.session [ 'my_dict'] current_dict.pop ('c') richiesta .session ['my_dict'] = current_dict –

+0

Penso che funzionerebbe, poiché impostando la chiave di primo livello della sessione la sessione noterebbe la modifica. –

-3

io non sono troppo sorpreso da questo. Credo che sia proprio come modificare il contenuto di una tupla:

a = (1,[2],3) 
print a 
>>> 1, [2], 3) 

a[1] = 4 
>>> Traceback (most recent call last): 
... File "<stdin>", line 1, in <module> 
... TypeError: 'tuple' object does not support item assignment 

print a 
>>> 1, [2], 3) 

a[1][0] = 4 
print a 
>>> 1, [4], 3) 

Ma grazie comunque.

+1

a) È possibile modificare il contenuto di un dizionario.b) il problema non è se sia possibile o meno una determinata variabile; il problema è che una volta modificato non è riconosciuto come tale da Django automaticamente –

8

Mi scuso per aver "fatto" una domanda a cui già conosco la risposta, ma questo è stato abbastanza frustrante che ho pensato che la risposta dovesse essere registrata sullo stackoverflow. Se qualcuno ha qualcosa da aggiungere alla mia spiegazione, assegnerò la "risposta". Non sono riuscito a trovare la risposta cercando in base al problema, ma dopo aver cercato in base alla risposta ho scoperto che il mio "problema" è documented behavior. Risulta anche another person had this problem.

Si scopre che SessionBase è un oggetto simile ai dizionari che tiene traccia di quando si modifica è chiavi, e imposta manualmente un attributo modified (c'è anche un accessed). Se si scherza con gli oggetti all'interno di quelle chiavi, tuttavia, SessionBase non ha modo di sapere che gli oggetti sono stati modificati e pertanto le modifiche potrebbero non essere memorizzate in qualsiasi backend che si sta utilizzando. (Sto usando un back-end del database, presumo che questo problema si applichi a tutti i backend, però.) Questo problema potrebbe non essere applicabile ai modelli, poiché il backend probabilmente sta memorizzando un riferimento al modello (e quindi riceverebbe eventuali modifiche quando è caricato il modello dal database), ma il problema si applica ai dizionari (e forse a qualsiasi altro tipo di python di base che deve essere memorizzato interamente nell'archivio delle sessioni.)

Il trucco è che ogni volta che si modificano oggetti nella sessione, il sessione non si nota, è necessario indicare esplicitamente la sessione che si è modificata:

>>> request.session.modified = True 

Spero che questo aiuti qualcuno.

Il modo in cui ho ottenuto intorno a questo è stato quello di incapsulare le azioni pop sulla sessione in un metodo che si prende cura dei dettagli (questo metodo accetta anche un parametro di visualizzazione in modo che le variabili di sessione possono essere specifiche per view):

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 
+2

Non c'è bisogno di scusarsi per aver risposto alle tue domande, in realtà è incoraggiato! – Flimm

Problemi correlati