2009-10-29 9 views
9

Tengo un modelo de datos fijo que tiene muchos campos de datos.¿Cómo almacenar pares de claves de nombre/valor arbitrarios en un modelo de Django?

 
class Widget(Models.model): 
    widget_owner = models.ForeignKey(auth.User) 
    val1 = models.CharField() 
    val2 = models.CharField() 
    ... 
    val568 = ... 

quiero meter aún más datos en este Widget al permitir que mis usuarios especifican campos de datos personalizados. ¿Cuál es una manera sensata de hacer esto? ¿Es una buena idea almacenar pares de nombre/valor donde el usuario puede especificar "campos de widget" adicionales? Mis pensamientos son seudo continuación:

 
data_types = ('free_text', 'date', 'integer', 'price') 
class CustomWidgetField(models.Model) 
    owner = ForeignKey(auth.User) 
    field_title = models.CharField(auth.User) 
    field_value_type = models.CharField(choices = data_types) 

class CustomWidgetValue(models.Model) 
    field_type = ForeignKey(CustomWidgetField) 
    widget = ForeignKey(Widget) 
    value = models.TextField() 

por lo que quiero dejar que cada usuario construir un nuevo tipo de campo de datos que se aplicará a la totalidad de sus widgets y luego especifique los valores para cada campo personalizado en cada widget. Probablemente tendré que hacer el filtrado/búsqueda en estos campos personalizados de la misma manera que lo haría en un campo nativo (que supongo que será mucho más lento que operar en campos nativos). Pero la escala es para tener unas pocas docenas de campos personalizados por Widget y cada Usuario solo tendrá unos miles de Widgets en su inventario. Puedo también, probablemente, la mayor parte del lote de búsqueda/filtrado en los campos personalizados en un script backend (tal vez.)

Respuesta

21

Considérese que representa todas las propiedades personalizadas con dict serializado. Lo usé en un proyecto reciente y funcionó muy bien.

class Widget(models.Model): 
     owner = models.ForeignKey(auth.User) 
     props = models.TextField(blank=True) # serialized custom data 

     @property 
     def props_dict(self): 
      return simplejson.loads(self.props) 

class UserProfile(models.Model) 
     user = models.ForeignKey(auth.User) 
     widget_fields = models.TextField(blank=True) # serialized schema declaration 
+0

Mientras que no es necesario para ordenar o filtro basado en el valor de los atributos personalizados, esta solución supondrá probablemente menos dolor de cabeza (y un mejor rendimiento) que los modelos WidgetField y WidgetValue. Podría limpiarse haciendo que los accesorios sean un tipo de campo personalizado que se serializa automáticamente y se deserializa en la carga/guardado. –

8

Parece que ha reinventado la tienda triple. Creo que es algo común, ya que seguimos la idea de la flexibilidad de la base de datos hasta su conclusión natural. Las tiendas triples tienden a ser bastante ineficientes en los sistemas de bases de datos relacionales, pero hay sistemas diseñados específicamente para ellos.

http://en.wikipedia.org/wiki/Triplestore

En las escalas que estamos hablando, su rendimiento es probable que sea aceptable, pero por lo general no escala bien sin una base de datos especializada.

+1

De acuerdo. Probablemente deberías considerar algo como la biblioteca Redland o rdflib (http://code.google.com/p/rdflib/wiki/IntroStore) en lugar de la capa db de django. El beneficio real de esto será usar lenguajes de consulta especializados, como SPARQL. –

2

En mi opinión, la mejor manera de lograr este tipo de modelo completamente extensible es realmente con EAV (Entidad, Atributo Valor). Básicamente es una forma de llevar una base de datos no relacional sin esquema a SQL. Puedes leer un montón más sobre esto en wikipedia, http://en.wikipedia.org/wiki/Entity-attribute-value_model, pero una de las mejores implementaciones en django es desde la base de código EveryBlock. Espero que sea una ayuda!

http://github.com/brosner/everyblock_code/blob/master/ebpub/ebpub/db/models.py

+0

1, el primer enlace de Wikipedia fue muy útil, en la prestación de la historia y la nomenclatura de este espacio problema común/solución - ayuda a uno darse cuenta de que esto no es en absoluto una nueva área. El segundo enlace está actualmente en 404'ing. – limist

+0

Tenga en cuenta que hay al menos dos aplicaciones de Django que proporcionan EAV: eav-django y django-eav. El primero se encuentra en https://bitbucket.org/neithere/eav-django/ y su autor aún participa activamente. – limist

0

Cuando tuve un objeto que podría ser totalmente personalizada según los usuarios, he creado un campo en el modelo que contendría algunos JSON en la columna. Luego puede serializar una y otra vez cuando necesite usarla o guardarla.

Sin embargo, sí lo hace más difícil de usar los datos en las consultas SQL.

Cuestiones relacionadas