2016-02-18 22 views
5

Ho recentemente aggiornato a Django 1.9 e ho provato ad aggiornare alcuni dei miei campi modello per utilizzare il JSONField integrato (sto usando PostgreSQL 9.4.5). Mentre stavo cercando di creare e aggiornare i campi del mio oggetto, mi sono imbattuto in qualcosa di strano. Qui è il mio modello:Django 1.9 JSONCampione aggiornamento aggiornamento

class Activity(models.Model): 
    activity_id = models.CharField(max_length=MAX_URL_LENGTH, db_index=True, unique=True) 
    my_data = JSONField(default=dict()) 

Ecco un esempio di quello che stavo facendo:

>>> from proj import models 
>>> test, created = models.Activity.objects.get_or_create(activity_id="foo") 
>>> created 
True 
>>> test.my_data['id'] = "foo" 
>>> test.save() 
>>> test 
<Activity: {"id": "foo"}> 
>>> test2, created2 = models.Activity.objects.get_or_create(activity_id="bar") 
>>> created2 
True 
>>> test2 
<Activity: {"id": "foo"}> 
>>> test2.activity_id 
'bar' 
>>> test.activity_id 
'foo' 

Sembra ogni volta che aggiorno ogni campo nel my_data, l'oggetto successivo creo stessa pre-popola con il dati da my_data dall'oggetto precedente. Ciò accade se utilizzo get_or_create o solo create. Qualcuno può spiegarmi cosa sta succedendo?

risposta

17

Il problema è che si sta usando default=dict(). I dizionari Python sono mutabili. Il dizionario predefinito viene creato una volta quando viene caricato il file dei modelli. Successivamente, eventuali modifiche apportate a instance.my_data modificano la stessa istanza, se utilizzano il valore predefinito.

La soluzione è utilizzare il callable dict come valore predefinito anziché dict().

class Activity(models.Model): 
    my_data = JSONField(default=dict) 

Il JSONField docs mettere in guardia su questo:

Se si dà il campo un default, assicurarsi che sia un richiamabile come dict (per impostazione predefinita vuoto) o un richiamabile che restituisce un dict (come una funzione). L'utilizzo errato di default={} crea un valore mutabile predefinito condiviso tra tutte le istanze di JSONField.

+0

Wow, pensavo di averlo cambiato in callable. Grazie per aver segnalato questo semplice errore! – user994013

Problemi correlati