¿Cómo almacenar un diccionario en un modelo Django?
-
03-07-2019 - |
Pregunta
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 uso subclases, necesitaré crear una clase completa cada vez que necesite un nuevo tipo de objeto, y eso no es bueno. También terminaré con muchas subclases solo para almacenar un par de campos adicionales.
Realmente siento que un diccionario sería el mejor enfoque, pero no hay nada en la documentación de Django sobre el almacenamiento de un diccionario en un modelo de Django (o no puedo encontrarlo).
¿Alguna pista?
Solución
Si en realidad está buscando un diccionario como datos arbitrarios, probablemente pueda usar una configuración de dos niveles con un modelo que sea un contenedor y otro modelo que sea pares clave-valor. Crearía una instancia del contenedor, crearía cada una de las instancias de valor clave y asociaría el conjunto de instancias de valor clave con la instancia de contenedor. Algo así 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 le permitirá acceder / buscar en las entrañas del diccionario utilizando la base de datos, mientras que una solución de pickle / serialización no lo hará.
Otros consejos
Si no necesita consultar con ninguno de estos datos adicionales, entonces puede almacenarlo como un diccionario serializado. Utilice repr
para convertir el diccionario en una cadena y eval
para volver a convertir la cadena en un diccionario. Tenga cuidado con la evaluación de que no hay datos de usuario en el diccionario, o use una implementación segura_eval.
Llegué a esta publicación por el cuarto resultado de Google para " objeto de tienda django "
Un poco tarde, pero django-picklefield me parece una buena solución.
Ejemplo de doc:
Para usar, solo define un campo en tu modelo:
>>> from picklefield.fields import PickledObjectField
>>> class SomeObject(models.Model):
>>> args = PickledObjectField()
y asigne lo que quiera (siempre que sea seleccionable) al campo:
>>> obj = SomeObject()
>>> obj.args = ['fancy', {'objects': 'inside'}]
>>> obj.save()
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
Usuario
from django.db import models
from jsonfield import JSONField
class MyModel(models.Model):
json = JSONField()
Como respondió Ned, no podrá consultar " algunos datos " si usa el enfoque de diccionario.
Si aún necesita almacenar diccionarios, el mejor método es la clase PickleField documentada en el nuevo libro de Marty Alchin Pro Django . Este método utiliza las propiedades de la clase Python para encurtir / desarmar un objeto de Python, solo a pedido, que se almacena en un campo modelo.
Lo básico de este enfoque es utilizar contibute_to_class
para agregar dinámicamente un nuevo campo a su modelo y usa getattr / setattr para realizar la serialización a pedido.
Uno de los pocos ejemplos en línea que podría encontrar que es similar es esta definición de JSONField .
No estoy muy seguro de la naturaleza del problema que estás tratando de resolver, pero suena curiosamente similar a BigTable Expando de Google App Engine .
Los Expandos le permiten especificar y almacenar campos adicionales en una instancia de objeto respaldada por base de datos en tiempo de ejecución. Para citar de 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 es compatible con Python y el marco Django. Podría valer la pena investigar si esta es la mejor manera de expresar sus modelos.
Los modelos tradicionales de bases de datos relacionales no tienen este tipo de flexibilidad de adición de columna. Si sus tipos de datos son lo suficientemente simples, puede romper con la filosofía tradicional RDBMS y piratear valores en una sola columna mediante 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. En particular, creará un one-to -una relación de clave externa para cada nivel de derivación.
Ser " no es igual a todas las instancias del modelo " me parece una buena combinación para una "base de datos libre de esquemas". CouchDB es el elemento secundario para ese enfoque y usted podría considerar eso.
En un proyecto, moví varias mesas que nunca jugaron muy bien con Django ORM a CouchDB y estoy bastante contento con eso. Yo uso couchdb-python sin ninguno de los módulos CouchDB específicos de Django. Se puede encontrar una descripción del modelo de datos aquí . El movimiento de cinco '' modelos '' en Django a 3 '' modelos '' en Django y una base de datos CouchDB " en realidad redujo ligeramente las líneas totales de código en mi aplicación.
Esta pregunta es antigua, pero tenía el mismo problema, terminé aquí y la respuesta elegida ya no pudo resolver mi problema.
Si desea almacenar diccionarios en Django o REST Api, ya sea para usarlos como objetos en su parte frontal, 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 esta pregunta .
Si usa esta estructura, sus datos ya estarán en el formato json apropiado para ser llamado en el front end con JSON.parse () en tu llamada ajax (o lo que sea).
Piénsalo, y encuentra las características comunes 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 se deben evitar, pero se deben alentar cuando tienen sentido.
El relleno de datos aleatorios en una tabla SQL no es inteligente, a menos que sean datos verdaderamente no relacionales. Si ese es el caso, define tu problema y podremos ayudarte.
Django-Geo incluye un " DictionaryField " puede ser útil:
http: / /code.google.com/p/django-geo/source/browse/trunk/fields.py?r=13#49
En general, si no necesita consultar a través de los datos, utilice un enfoque desnormalizado para evitar consultas adicionales. ¡La configuración del usuario es un buen ejemplo!
Si está usando Postgres, puede usar un campo hstore: https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/fields/#hstorefield .
Uso un campo de texto y json.loads()
/json.dumps()
models.py
import json
from django.db import models
class Item(models.Model):
data = models.TextField(blank=True, null=True, default='{}')
def save(self, *args, **kwargs):
## load the current string and
## convert string to python dictionary
data_dict = json.loads(self.data)
## do something with the dictionary
for something in somethings:
data_dict[something] = some_function(something)
## if it is empty, save it back to a '{}' string,
## if it is not empty, convert the dictionary back to a json string
if not data_dict:
self.data = '{}'
else:
self.data = json.dumps(data_dict)
super(Item, self).save(*args, **kwargs)