2009-07-11 4 views
10

Fondamentalmente, ho un modello in cui ho creato una superclasse che molte altre classi condividono, e quindi ciascuna di queste classi ha alcune caratteristiche uniche che differiscono l'una dall'altra. Diciamo che la classe A è la superclasse, e la classe B, C e D sono figli di quella classe.Ereditarietà modello Django E chiavi esterne

Sia la classe B che la classe C possono avere multipli della classe D, tuttavia ho visto che è meglio mettere la relazione di chiave esterna nella classe D, che quindi si riferisce alla sua classe genitore. Ora in altre lingue, potrei semplicemente dire che ha una relazione ForeignKey con la classe A, e quindi il linguaggio riconosce il vero tipo delle classi. Tuttavia, non penso che sia così che funziona con Python.

Qual è il modo migliore di seguire questo problema?

EDIT: Qui è grosso modo quello che voglio dire ...

class A(models.Model): 
    field = models.TextField() 

class B(A): 
    other = <class specific functionality> 

class C(A): 
    other2 = <different functionality> 

class D(A): 
    #I would like class D to have a foreign key to either B or C, but not both. 

In sostanza, classe B e di classe C hanno entrambi classe multipla D's. Ma una particolare classe D appartiene solo a una di esse.

+0

si potrebbe spiegare il motivo per cui avete bisogno di eredità? – Evgeny

+0

C'è una domanda correlata ha alcune belle risposte che possono aiutare: https://stackoverflow.com/questions/1114767/django-model-inheritance-and-foreign-keys – Miranda

risposta

3

Dal Django Docs:

Per esempio, se si stavano costruendo un database di "luoghi", si potrebbe costruire roba abbastanza standard come l'indirizzo, il numero di telefono , ecc il database. Quindi, se si voleva costruire un database di ristoranti in cima alle posti, invece di ripetere se stessi e replicare quei campi nel modello ristorante, si potrebbe fare Ristorante hanno un OneToOneField a Place (a causa di un ristorante "è un" posto, infatti, per gestire questo si dovrebbe in genere utilizzare l'ereditarietà, che coinvolge una relazione uno-a-uno implicita).

Normalmente, si sarebbe solo avere Restaurant ereditare da Place.Purtroppo, è necessario quello che io considero un hack: fare un riferimento uno-a-uno da sottoclasse alla superclasse (Restaurant-Place)

+0

Non django fornisce un riferimento uno-a-uno di default? per esempio. per i modelli ereditati con più tabelle, "restaurant.place" restituisce l'istanza corrispondente di Place, senza che l'utente debba definire alcuna relazione diversa dall'ereditarietà. –

+3

forse lo fa ora, ma non credo che sia stato fatto in * 2009 *. – geowa4

+0

Vedo, grazie! xxx –

1

vedo un problema qui:

class D(A): 
    #D has foreign key to either B or C, but not both. 

non può farlo. Dovrai aggiungere entrambi perché nelle colonne SQL deve essere definito esattamente.

Anche se i modelli ereditati come te hanno compilato con syncdb - non sembrano comportarsi come ci si aspetterebbe - almeno non potrei farli funzionare. Non so spiegare perché.

Ecco come funziona FK in Django

class A(models.Model): 
    a = models.CharField(max_length=5) 

class B(models.Model): 
    a = model.ForeignKey(A, related_name='A') 
    b = models.CharField(max_length=5) 

class D(models.Model): 
    a = model.ForeignKey(A, related_name='A') 
    parent = model.ForeignKey(B, related_name='D') 

questo modo è possibile avere in modo efficace multipli di D in B.

Inheritance in modelli (ad esempio di classe B (A)) non funziona come Lo aspetterei. Forse qualcun altro può spiegarlo meglio.

Dai un'occhiata alla pagina this doc. Riguarda la relazione molti-a-uno in django.

b = B() 
b.D_set.create(...) 
+0

Il mio problema è, vorrei che la classe D appartenga a o una Classe A o una Classe B e non entrambi. Chiarirò nella mia domanda – AlbertoPL

1

Un modo per farlo è quello di aggiungere una classe intermedia come segue:

class A(Model): 
    class Meta(Model.Meta): 
     abstract = True 
    # common definitions here 

class Target(A): 
    # this is the target for links from D - you then need to access the 
    # subclass through ".b" or ".c" 
    # (no fields here) 

class B(Target): 
    # additional fields here 

class C(Target): 
    # additional fields here   

class D(A): 
    b_or_c = ForeignKey(Target) 
    def resolve_target(self): 
     # this does the work for you in testing for whether it is linked 
     # to a b or c instance 
     try: 
      return self.b_or_c.b 
     except B.DoesNotExist: 
      return self.b_or_c.c 

Utilizzando una classe intermedia (Target) garantisce che ci sarà solo un link da D a B o C. fa, che ha senso? Vedere http://docs.djangoproject.com/en/1.2/topics/db/models/#model-inheritance per ulteriori informazioni.

Nel tuo database ci saranno tabelle per Target, B, C e D, ma non A, perché è stato contrassegnato come astratto (invece, le colonne relative agli attributi su A saranno presenti in Target e D).

[Warning: Non ho effettivamente provato questo codice - qualche correzione benvenuti!]

+0

Molto hacky. Anche se funzionerebbe. – clime