Django 1.9 JSONField comportamiento de actualización

Recientemente he actualizado a Django 1.9 y he intentado actualizar algunos de mis campos de modelo para usar el JSONField integrado (estoy usando PostgreSQL 9.4.5). Mientras intentaba crear y actualizar los campos de mi objeto, encontré algo peculiar. Aquí está mi modelo:

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

Aquí hay un ejemplo de lo que estaba haciendo:

 >>> 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  >>> test2, created2 = models.Activity.objects.get_or_create(activity_id="bar") >>> created2 True >>> test2  >>> test2.activity_id 'bar' >>> test.activity_id 'foo' 

Parece que cada vez que actualizo cualquier campo en my_data , el siguiente objeto que creo se rellena my_data con los datos de my_data del objeto anterior. Esto sucede si uso get_or_create o simplemente create . ¿Puede alguien explicarme lo que está pasando?

El problema es que estás usando default=dict() . Los diccionarios de Python son mutables. El diccionario predeterminado se crea una vez cuando se carga el archivo de modelos. Después de eso, cualquier cambio en instance.my_data alterará la misma instancia, si están usando el valor predeterminado.

La solución es usar el dict invocable como predeterminado en lugar de dict() .

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

Los documentos de JSONField advierten sobre esto:

Si asigna un default al campo, asegúrese de que sea un llamable como dict (para un valor predeterminado vacío) o un llamador que devuelva un dict (como una función). El uso incorrecto de default={} crea un valor predeterminado mutable que se comparte entre todas las instancias de JSONField .

 from django_postgres_extensions.models.expressions import Key obj = Product.objectsannotate(Key('description', 'Details')).get() obj = Product.objects.annotate(Key('description', 'Details__Rating')).get() obj = Product.objects.annotate(Key('description', 'Tags__1')).get() Product.objects.update(description__ = {'Industry': 'Movie', 'Popularity': 'Very Popular'}) Product.objects.update(description__del ='Details') Product.objects.update(description__del = 'Details__Release') Product.objects.update(description__del='Tags__1')