2008-12-31 25 views
44

Necesito almacenar algunos datos en un modelo de Django. Estos datos no son iguales a todas las instancias del modelo.¿Cómo almacenar un diccionario en un modelo de Django?

Al principio pensé en subclasificar el modelo, pero trato de mantener la aplicación flexible. Si utilizo subclases, tendré que 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 creo 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?

+6

"algunos datos": poco definidos. Sin algún modelo de datos u otra pista, no hay respuesta. –

Respuesta

32

Si realmente es un diccionario como los datos arbitrarios que está buscando, probablemente pueda utilizar una configuración de dos niveles con un modelo que es un contenedor y otro modelo con pares clave-valor. Debería crear una instancia del contenedor, crear cada una de las instancias de valor-clave y asociar el conjunto de instancias de clave-valor 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 dejará que el acceso/buscar las entrañas del diccionario utilizando DB mientras que un pepinillo/serializar solución no lo hará.

+4

El único inconveniente es que se generará una consulta DB adicional –

+2

Otro inconveniente es que tiene exactamente un "nivel" de datos, no puede crear datos complejos de varios niveles de estilo JSON. (pero buena idea, no obstante) –

+6

Encontré una buena extensión de esta solución: https://djangosnippets.org/snippets/2451/ este tipo extendió el diccionario a todas las funciones del diccionario pitónico –

14

Si no necesita consultar alguno de estos datos adicionales, puede almacenarlo 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 que no hay datos de usuario en el diccionario, o use una implementación safe_eval.

2

Piénselo detenidamente y descubra las características comunes de cada conjunto de datos ... luego defina su modelo. Puede requerir el uso de subclases o no. Las claves foráneas que representan aspectos comunes no deben evitarse, sino que deben promoverse cuando tengan sentido.

Rellenar datos aleatorios en una tabla SQL no es inteligente, a menos que se trate de datos verdaderamente no relacionales. Si ese es el caso, defina su problema y podremos ayudarlo.

+1

+1: no coloques objetos de Python en una mesa al azar. –

4

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

Las expansiones le permiten especificar y almacenar campos adicionales en una instancia de objeto respaldada por una 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 tanto con Python como con el framework Django. Puede 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 columnas. Si sus tipos de datos son lo suficientemente simples, podría salirse de la filosofía RDBMS tradicional y piratear los valores en una sola columna a través de la serialización como propone @Ned Batchelder; sin embargo, si tiene tiene para usar un RDBMS, la herencia del modelo Django es probablemente el camino a seguir. En particular, creará la relación a one-to-one foreign key para cada nivel de derivación.

7

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

Si aún necesita almacenar diccionarios, 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 la clase Python para desenterrar/desengrasar un objeto python, solo a pedido, que se almacena en un campo de modelo.

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

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

3

Al ser "no igual a todas las instancias del modelo" me suena como una buena coincidencia para una "base de datos libre de esquemas". CouchDB es el poster de este enfoque y usted podría considerar eso.

En un proyecto moví varias tablas que nunca se jugaron muy bien con el Django ORM a CouchDB y estoy muy 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 here. El movimiento de cinco "modelos" en Django a 3 "modelos" en Django y una "base de datos" de CouchDB realmente redujo el total de líneas de código en mi aplicación.

3

Acepto que debe contener el relleno de datos estructurados en una sola columna. Pero si debe hacer eso, Django tiene un XMLField incorporado.

También hay JSONField en Django snipplets.

10

Vine a este mensaje por resultado 4rth de Google de "objeto de almacén de Django"

Un poco tarde, pero django-picklefield parece buena solución para mí.

Ejemplo de doc:

de usar, basta definir un campo en su modelo:

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

y asignar lo que quiera (siempre y cuando sea estibables) al campo:

>>> obj = SomeObject() 
>>> obj.args = ['fancy', {'objects': 'inside'}] 
>>> obj.save() 
6

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

Por conveniencia, copié las instrucciones simples.

Instalar

pip install jsonfield 

Uso

from django.db import models 
from jsonfield import JSONField 

class MyModel(models.Model): 
    json = JSONField() 
Cuestiones relacionadas