Cómo almacenar un diccionario en un modelo Django?


Necesito almacenar algunos datos en un modelo Django. Estos datos no son iguales a todas las instancias del modelo.

Al principio pensé en subclasificar el modelo, pero estoy tratando de mantener la aplicación flexible. Si utilizo subclases, necesitaré crear una clase entera cada vez que necesite un nuevo tipo de objeto, y eso no es bueno. También terminaré con un montón de subclases solo para almacenar un par de campos adicionales.

Realmente siento que un diccionario sería el mejor enfoque, pero hay nada en la documentación de Django acerca de almacenar un diccionario en un modelo Django (o no puedo encontrarlo).

¿Alguna pista?
Author: Paul D. Waite, 2008-12-31

12 answers

Si realmente es un diccionario como datos arbitrarios lo que está buscando, probablemente puede usar una configuración de dos niveles con un modelo que es un contenedor y otro modelo que es pares clave-valor. Crearía una instancia del contenedor, crearía cada una de las instancias clave-valor y asociaría el conjunto de instancias clave-valor con la instancia del contenedor. Algo como:

class Dicty(models.Model):
    name      = models.CharField(max_length=50)

class KeyVal(models.Model):
    container = models.ForeignKey(Dicty, db_index=True)
    key       = models.CharField(max_length=240, db_index=True)
    value     = models.CharField(max_length=240, db_index=True)

No es bonito, pero te permitirá acceder / buscar las entrañas del diccionario usando la base de datos mientras que un pepinillo / serializar solución no.

 34
Author: Parand,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-31 08:19:28

Si no necesita consultar ninguno de estos datos adicionales, puede almacenarlos como un diccionario serializado. Use repr para convertir el diccionario en una cadena, y eval para volver a convertir la cadena en un diccionario. Tenga cuidado con eval de que no haya datos de usuario en el diccionario, o use una implementación safe_eval.

 14
Author: Ned Batchelder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-31 03:39:18

Llegué a este post por el resultado 4rth de Google a"django store object"

Un poco tarde, pero django-picklefield me parece una buena solución.

Ejemplo de doc:

Para usar, simplemente defina un campo en su modelo:

>>> from picklefield.fields import PickledObjectField
>>> class SomeObject(models.Model):
>>>     args = PickledObjectField()

Y asigna lo que quieras (siempre y cuando sea seleccionable) al campo:

>>> obj = SomeObject()
>>> obj.args = ['fancy', {'objects': 'inside'}]
>>> obj.save()
 11
Author: Stéphane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-19 10:10:04

Otra solución limpia y rápida se puede encontrar aquí: https://github.com/bradjasper/django-jsonfield

Por conveniencia copié las sencillas instrucciones.

Instalar

pip install jsonfield

Uso

from django.db import models
from jsonfield import JSONField

class MyModel(models.Model):
    json = JSONField()
 11
Author: odedfos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-31 12:50:28

Como Ned respondió, no podrá consultar "algunos datos" si utiliza el enfoque de diccionario.

Si todavía necesita almacenar diccionarios, entonces el mejor enfoque, de lejos, es la clase PickleField documentada en el nuevo libro de Marty Alchin Pro Django. Este método utiliza las propiedades de clase de Python para pickle / desempaquetar un objeto de Python, solo bajo demanda, que se almacena en un campo de modelo.

Lo básico de este enfoque es usar el contibute_to_class método para agregar dinámicamente un nuevo campo a su modelo y utiliza getattr / setattr para hacer la serialización bajo demanda.

Uno de los pocos ejemplos en línea que pude encontrar que es similar es esta definición de un JSONField.

 7
Author: Van Gale,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-31 07:44:46

No estoy seguro exactamente de la naturaleza del problema que está tratando de resolver, pero suena curiosamente similar a BigTable Expando de Google App Engine.

Los Expandos permiten especificar y almacenar campos adicionales en una instancia de objeto respaldada por una base de datos en tiempo de ejecución. Para citar los documentos:

import datetime
from google.appengine.ext import db

class Song(db.Expando):
  title = db.StringProperty()

crazy = Song(title='Crazy like a diamond',
             author='Lucy Sky',
             publish_date='yesterday',
             rating=5.0)

crazy.last_minute_note=db.Text('Get a train to the station.')

Google App Engine actualmente soporta Python y el framework Django. Podría valer la pena investigar si esta es la mejor manera de expresar su modelo.

Los modelos de bases de datos relacionales tradicionales no tienen este tipo de flexibilidad de adición de columnas. Si sus tipos de datos son lo suficientemente simples, podría romper con la filosofía tradicional de RDBMS y hackear valores en una sola columna a través de la serialización como @Ned Batchelder propone; sin embargo, si tiene para usar un RDBMS, la herencia del modelo Django es probablemente el camino a seguir. Notably, it will create a one-to-one foreign key relation for each level of derivation.

 5
Author: cdleary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:50

Estoy de acuerdo en que debe abstenerse de rellenar datos estructurados de otra manera en una sola columna. Pero si tienes que hacer eso, Django tiene un build-in XMLField.

También hay JSONField en los fragmentos de Django.

 3
Author: muhuk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-13 18:05:44

Ser "no igual a todas las instancias del modelo" me suena como una buena combinación para una "base de datos libre de esquemas". CouchDB es el hijo póster de ese enfoque y podrías considerarlo.

En un proyecto moví varias mesas que nunca jugaron muy bien con el Django OR a CouchDB y estoy bastante contento con eso. Utilizo couchdb-python sin ninguno de los módulos CouchDB específicos de Django. Una descripción del modelo de datos se puede encontrar aquí. El el movimiento de cinco " modelos "en Django a 3" modelos "en Django y una" base de datos " CouchDB realmente redujo ligeramente las líneas totales de código en mi aplicación.

 3
Author: max,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-09 11:34:37

Piénsalo y encuentra los puntos en común de cada conjunto de datos... luego define tu modelo. Puede requerir el uso de subclases o no. Las claves foráneas que representan puntos en común no deben evitarse, sino alentarse cuando tienen sentido.

Rellenar datos aleatorios en una tabla SQL no es inteligente, a menos que sean datos verdaderamente no relacionales. Si ese es el caso, defina su problema y tal vez podamos ayudarlo.

 2
Author: Daniel Naab,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-31 05:54:12

Django-Geo incluye un "DictionaryField" que podría ser útil:

Http://code.google.com/p/django-geo/source/browse/trunk/fields.py?r=13#49

En general, si no necesita realizar consultas a través de los datos, use un enfoque desnormalizado para evitar consultas adicionales. La configuración del usuario es un buen ejemplo!

 2
Author: jb.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-13 16:50:37

Si está utilizando Postgres, puede usar un campo hstore: https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/fields/#hstorefield .

 1
Author: Scott Stafford,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-30 19:36:59

Esta pregunta es antigua, pero yo estaba teniendo el mismo problema, terminó aquí y la respuesta elegida ya no podía resolver mi problema.

Si desea almacenar diccionarios en Django o REST Api, ya sea para ser utilizados como objetos en su front end, o porque sus datos no necesariamente tendrán la misma estructura, la solución que utilicé puede ayudarlo.

Al guardar los datos en su API, use json.dump () método para poder almacenarlo en un formato json adecuado, como se describe en este pregunta.

Si utiliza esta estructura, sus datos ya estarán en el formato json apropiado para ser llamados en el front end con JSON.parse () en tu llamada ajax (o lo que sea).

 0
Author: Lucas Colzani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-02 08:56:20