2015-05-31 13 views
7

ContestoQuali sono i pro e i contro dell'uso di GenericForeignKey rispetto all'ereditarietà multipla rispetto a OneToOneField?

Sono in procinto di modellare i miei dati utilizzando i modelli Django. Il modello principale è un Article. Tiene il contenuto reale.

Quindi ogni Article deve essere collegato a un gruppo di articoli. Quel gruppo può essere uno Blog, uno Category uno Portfolio o uno Story. Ogni Article deve essere collegato a uno, ed esattamente uno di quelli. Cioè, un blog, una categoria o una storia. Questi modelli hanno campi e caratteristiche molto diversi.

Ho pensato a tre modi per raggiungere questo obiettivo (e uno bonus che sembra davvero sbagliato).

Opzione 1: un generico stranieri chiave

Come in django.contrib.contenttypes.fields.GenericForeignKey. Si sarebbe simile a questa:

class Category(Model): 
    # some fields 

class Blog(Model): 
    # some fields 

class Article(Model): 
    group_type = ForeignKey(ContentType) 
    group_id = PositiveIntegerField() 
    group = GenericForeignKey('group_type', 'group_id') 
    # some fields 

Sul lato del database, che significa nessuna relazione esiste in realtà tra i modelli, la loro applicazione da Django.

Opzione # 2: l'eredità Multitable

gruppi di articoli Eseguire tutti ereditano da un modello ArticleGroup. Questo sarebbe simile a questa:

class ArticleGroup(Model): 
    group_type = ForeignKey(ContentType) 

class Category(ArticleGroup): 
    # some fields 

class Blog(ArticleGroup): 
    # some fields 

class Article(Model): 
    group = ForeignKey(ArticleGroup) 
    # some fields 

Sul lato database, questo crea una tabella aggiuntiva per ArticleGroup, quindi Category e Blog avere una chiave esterna implicito a quel tavolo come loro chiave primaria.

Sidenote: So che c'è a package che automatizza la contabilità di tali costruzioni.

Opzione # 3: OneToOneFields manuali

Dal punto di vista del database, è equivalente a opzione # 2. Ma nel codice, tutte le relazioni sono rese esplicite:

class ArticleGroup(Model): 
    group_type = ForeignKey(ContentType) 

class Category(Model): 
    id = OneToOneField(ArticleGroup, primary_key=True) 
    # some fields 

class Blog(Model): 
    id = OneToOneField(ArticleGroup, primary_key=True) 
    # some fields 

class Article(Model): 
    group = ForeignKey(ArticleGroup) 
    # some fields 

io non vedo quale sarebbe il punto di che, oltre a fare esplicito ciò che la magia eredità di Django fa implicitamente.

Bonus: più colonne

Sembra abbastanza sporca così ho aggiungerlo come bonus, ma sarebbe anche possibile definire una ForeignKey nullable a ciascuno dei Category, Blog, ... direttamente sul Modello Article.

Quindi ...

... non posso davvero decidere tra quelli. Quali sono i pro e i contro di ciascun approccio? Ci sono delle buone pratiche? Ho perso un approccio migliore?

Se è importante, sto utilizzando Django 1.8.

risposta

4

Sembra che nessuno avesse consigli da condividere su quello. Alla fine ho scelto l'opzione multicolonna, nonostante abbia detto che sembrava brutta. Tutto si riduceva a 3 elementi:

  • Esecutività basata su database.
  • Il modo in cui Django ORM funziona con i diversi costrutti.
  • Le mie proprie esigenze (ovvero, query di raccolta sul gruppo per ottenere l'elenco di elementi e singole query sugli elementi per ottenere il gruppo).

Opzione # 1

  • non possano essere attuate a livello di database.
  • Potrebbe essere efficiente sulle query perché il modo in cui è costruito non rientra nelle normali insidie ​​di chiavi esterne generiche. Questi accadono quando gli articoli sono generici, non le raccolte.
  • Tuttavia, a causa di come ORM gestisce GFK, è impossibile utilizzare un gestore personalizzato, di cui ho bisogno perché i miei articoli sono tradotti utilizzando django-hvad.

Opzione # 2

  • possano essere attuate a livello di database.
  • Potrebbe essere un po 'efficiente, ma si scontra con le limitazioni ORM, che chiaramente non è costruito attorno a questo uso. A meno che non usi molto il extra() o le query personalizzate, ma a un certo punto non c'è più motivo di usare un ORM.

Opzione # 3

  • sarebbe in realtà essere un po 'meglio di 2 #, come fare le cose esplicito consente l'ottimizzazione delle query più facile durante l'utilizzo del ORM.

multicolonna

  • risulta non essere così male. Può essere applicato a livello di database (vincoli FK più un controllo CHECK manuale per garantire che solo una delle colonne non sia nulla).
  • Facile ed efficiente. Una singola query intuitiva fa il lavoro: select_related('category', 'blog', ...).
  • Anche se ha il problema di essere più difficile da estendere (qualsiasi nuovo tipo richiede la modifica della tabella Article) e limitando il numero possibile di tipi, è improbabile che li incontri.

Spero che aiuti chiunque con lo stesso dilemma e sia ancora interessato a sentire altre opinioni.

+1

Sono d'accordo: l'opzione a più colonne è la migliore finché si prevede di avere solo un numero limitato di classi a cui potrebbe essere collegato.Per questo caso d'uso, GFK è male IMO, perché crea un buco nell'integrità del database e rende le query al di fuori di Django particolarmente difficili. – spookylukey

Problemi correlati