2009-10-29 7 views
9

Ho un modello dati fisso che ha molti campi dati.Come memorizzare coppie di chiavi arbitrarie nome/valore in un modello Django?

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

Voglio racchiudere ancora più dati in questo Widget consentendo ai miei utenti di specificare campi dati personalizzati. Qual è un modo corretto per farlo? Sta memorizzando coppie nome/valore in cui l'utente può specificare ulteriori "campi widget" una buona idea? I miei pensieri sono al di sotto pseudo:

 
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() 

quindi voglio lasciare che ogni utente a costruire un nuovo tipo di campo dati che si applica a tutti i loro widgets e quindi specificare i valori per ogni campo personalizzato in ciascun widget. Probabilmente dovrò fare il filtraggio/ricerca su questi campi personalizzati proprio come farei su un campo nativo (che presumo sarà molto più lento che operare su campi nativi). Ma la scala è di avere qualche dozzina di campi personalizzati per Widget e ogni utente avrà solo poche migliaia di widget nel proprio inventario. Probabilmente posso anche batch la maggior parte della ricerca/filtraggio sui campi personalizzati in uno script backend (forse)

risposta

21

Considerare la rappresentazione di tutte le proprietà personalizzate con dict serializzato. L'ho usato in un recente progetto e ha funzionato molto bene.

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

Finché non è necessario ordinare o filtrare in base al valore degli attributi personalizzati, questa soluzione comporterà probabilmente meno mal di testa (e prestazioni migliori) rispetto ai modelli WidgetField e WidgetValue. Potrebbe essere ripulito facendo di puntelli un tipo di campo personalizzato che serializza automaticamente e deserializza se stesso in caricamento/salvataggio. –

8

Sembra che tu abbia reinventato il triplo store. Penso che sia una cosa comune, poiché seguiamo l'idea della flessibilità del database fino alla sua naturale conclusione. I negozi tripli tendono ad essere abbastanza inefficienti nei sistemi di database relazionali, ma esistono sistemi progettati appositamente per loro.

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

alle scale si sta parlando, le prestazioni è probabile che sia accettabile, ma non lo fanno in genere in scala bene senza un DB specializzata.

+1

concordato. Probabilmente dovresti prendere in considerazione qualcosa come la libreria Redland o rdflib (http://code.google.com/p/rdflib/wiki/IntroStore) anziché il livello db di django. Il vero vantaggio di questo sarà l'utilizzo di linguaggi di query specializzati, come SPARQL. –

2

A mio parere, il modo migliore per ottenere questo tipo di modello completamente estensibile è in realtà con EAV (Entità, Attributo, Valore). È fondamentalmente un modo per portare a SQL un database non relazionale schemaless. Puoi leggere un sacco di informazioni su di esso su wikipedia, http://en.wikipedia.org/wiki/Entity-attribute-value_model ma una delle migliori implementazioni in django è la base di codice EveryBlock. Spero sia un aiuto!

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

+0

+1, il primo collegamento wikipedia è stato molto utile, nel fornire la storia e la nomenclatura di questo problema comune/spazio soluzione - aiuta a capire che questa non è affatto una nuova area. Il secondo link è attualmente 404'ing. – limist

+0

Nota che esistono almeno due app di Django che forniscono EAV: eav-django e django-eav. Il primo è su https://bitbucket.org/neithere/eav-django/ e il suo autore è ancora attivamente coinvolto. – limist

0

Quando ho avuto un oggetto che può essere completamente personalizzata dagli utenti, ho creato un campo sul modello che conterrebbe alcuni JSON nella colonna. Quindi puoi semplicemente serializzare avanti e indietro quando devi usarlo o salvarlo.

Tuttavia, rende più difficile l'utilizzo dei dati nelle query SQL.

Problemi correlati