Django Multi-Table Inheritance VS Specificando esplicita OnetoOne Relationship nei modelli

StackOverflow https://stackoverflow.com/questions/1796556

  •  22-09-2019
  •  | 
  •  

Domanda

Spero tutto questo ha un senso :) io chiarire attraverso i commenti, se necessario. Inoltre, Sto sperimentando con testo in grassetto in questa domanda, e permetterà di modificare fuori se io (o voi) trovo distrazione. Con quella di mezzo ...

Utilizzando django.contrib.auth ci dà utente e gruppo, tra le altre cose utili che non posso fare a meno (come la messaggistica di base).

Nella mia app ho diversi tipi di utenti. Un utente può essere di un solo tipo. Questo sarebbe essere facilmente gestite da gruppi, con un po 'di attenzione in più. Tuttavia, questi utenti diversi sono legati gli uni agli altri nelle gerarchie / relazioni.

Diamo uno sguardo a questi utenti: -

presidi - utenti "alto livello"

Gli amministratori - ogni amministratore riferisce ad un Principal

Coordinatori - ciascuno rapporti coordinatore a un amministratore

Oltre a questi Ci sono altri tipi di utenti che non sono direttamente collegati , ma può ottenere legati in seguito. Ad esempio, "Società" è un altro tipo di utente, e può avere diverse "Prodotti", e dei prodotti può essere controllato da un "coordinatore". "Acquirente" è un altro tipo di utente che possono acquistare i prodotti.

Ora tutto questo gli utenti hanno vari altri attributi, alcuni dei quali sono comuni a tutti i tipi di utenti e alcuni dei quali sono distinti a un solo tipo di utente . Per esempio, tutti i tipi di utenti devono avere un indirizzo. D'altra parte, solo l'utente principale appartiene ad una "BranchOffice".

Un altro punto, che è stato detto sopra, è che un utente può essere solo di un tipo .

L'applicazione anche ha la necessità di tenere traccia di chi ha creato e / o presidi modificati, gli amministratori, i coordinatori, aziende, prodotti, ecc . (Ecco, questo è più di due collegamenti al modello User.)

In questo scenario, è una buona idea usare multi-tavolo l'eredità di Django nel modo seguente: -

from django.contrib.auth.models import User
class Principal(User):
    #
    #
    #    
    branchoffice = models.ForeignKey(BranchOffice)
    landline = models.CharField(blank=True, max_length=20)    
    mobile = models.CharField(blank=True, max_length=20)
    created_by = models.ForeignKey(User, editable=False, blank=True, related_name="principalcreator")    
    modified_by = models.ForeignKey(User, editable=False, blank=True, related_name="principalmodifier")
    #
    #
    #

O devo andare a fare in questo modo: -

class Principal(models.Model):
    #
    #
    #
    user = models.OneToOneField(User, blank=True)
    branchoffice = models.ForeignKey(BranchOffice)
    landline = models.CharField(blank=True, max_length=20)    
    mobile = models.CharField(blank=True, max_length=20)
    created_by = models.ForeignKey(User, editable=False, blank=True, related_name="principalcreator")    
    modified_by = models.ForeignKey(User, editable=False, blank=True, related_name="principalmodifier")
    #
    #
    #

Si prega di tenere a mente che ci sono altri tipi di utenti che sono collegati tramite chiavi esterne, ad esempio: -

class Administrator(models.Model):
    #
    #
    #
    principal = models.ForeignKey(Principal, help_text="The supervising principal for this Administrator")
    user = models.OneToOneField(User, blank=True)
    province = models.ForeignKey(         Province)
    landline = models.CharField(blank=True, max_length=20)    
    mobile = models.CharField(blank=True, max_length=20)
    created_by = models.ForeignKey(User, editable=False, blank=True, related_name="administratorcreator")    
    modified_by = models.ForeignKey(User, editable=False, blank=True, related_name="administratormodifier")

Sono consapevole che Django fa uso di una relazione uno-a-uno per il multi-ereditarietà delle tabelle dietro le quinte. Io non sono solo qualificato sufficiente per decidere quale è un approccio più suono.

È stato utile?

Soluzione

Mi piacerebbe approfondire la soluzione @thornomad.

L'estensione classe User di Django direttamente può causare tutti i tipi di problemi con i meccanismi django.auth interni. Quello che ho fatto in una situazione simile è precisamente ciò che @thornomad suggerisce - ho fatto il mio proprio modello ProfiloUtente legato uno-a-uno con il modello User Django, in cui tenevo i dati utente aggiuntivi e da cui ho ereditato modelli per i diversi tipi di utenti.

qualcosa per soddisfare quello che hai descritto:

class UserProfile(models.Model):
    user = models.OneToOneField(User, blank=True, related_name='profile')
    class Meta:
        abstract = True


class PositionHolderUserProfile(UserProfile):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    landline = models.CharField(blank=True, max_length=20)    
    mobile = models.CharField(blank=True, max_length=20)
    created_by = models.ForeignKey(PositionHolderUserProfile, editable=False, blank=True, related_name="created_users")    
    modified_by = models.ForeignKey(PositionHolderUserProfile, editable=False, blank=True, related_name="modified_users")

class Principal(PositionHolderUserProfile):
    branchoffice = models.ForeignKey(BranchOffice)

class Administrator(PositionHolderUserProfile):
    superior = models.ForeignKey(Principal, related_name="subordinates")
    province = models.ForeignKey(Province)

class Coordinator(PositionHolderUserProfile):
    superior = models.ForeignKey(Administrator, related_name="subordinates")


class Company(UserProfile):
    name = models.CharField(max_length=50)

class Product(models.Model):
    name = models.CharField(max_length=50)
    produced_by = models.ForeignKey(Company)

class Buyer(UserProfile):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    products_bought = models.ManyToManyField(Product)

Altri suggerimenti

Recentemente ho passato ad utilizzare modelli che ereditano off di contrib.auto.models.User. La mia osservazione generale è che, in teoria, sono grandi, ma a volte non ottengono auto-magicamente trattati come se si suppone che.

Credo che la vostra decisione per quanto riguarda l'eredità vs OnetoOne si riduce a questo:

  • voglio avere Django fare automaticamente qualcosa di destra il 95% del tempo, e la necessità di eseguire il debug che altro 5%

-OR -

  • Voglio fare qualcosa manualmente me stesso al 100% del tempo

Se non avete visto, il blog di Scott Barham ha un grande post su ereditare off di utente, e anche la costruzione di un costume back-end per assicurarsi che il vostro oggetto personalizzato viene riconsegnato - l'estensione del Django utente

Inoltre di interesse dovrebbe essere il campo AutoOneToOne fornito da django-fastidioso . Si tratta di una sorta di ibrido tra i due approcci qui -. Non c'è alcuna eredità in atto, ma Django sta prendendo cura di creare l'abbinamento OneToOneField se non è presente

Inoltre, thornomad fa fare un buon punto sulla ridondanza nei tuoi modelli. Si potrebbe facilmente implementare una classe astratta per la pulizia che come modo (supponendo che si sta facendo OnetoOne manuale):

class BaseExtendedUser(models.Model):
    user = models.OneToOneField(User, blank=True, related_name='profile')
    landline = models.CharField(blank=True, max_length=20)    
    mobile = models.CharField(blank=True, max_length=20)
    created_by = models.ForeignKey(User, editable=False, blank=True, related_name="created_users")    
    modified_by = models.ForeignKey(User, editable=False, blank=True, related_name="modified_users")

    class Meta:
        abstract = True

class Administrator(BaseExtendedUser):
    province = models.ForeignKey(Province)

class Principal(BaseExtendedUser):
    branchoffice = models.ForeignKey(BranchOffice)

Non credo che avrei ereditato il modello User, piuttosto utilizzare un UserProfile personalizzata - lasciando da solo il modello contrib.auth. Con il modello UserProfile personalizzato, è possibile impostare un di base profilo utente modello che può essere una parte di tutti i diversi tipi di utente.

Solo guardando in fretta, troppo, vorrei guardare con attenzione a tutti i modelli che ripetono tutti gli stessi campi (come gli ultimi due modelli Principle e Administrator). Combinando la funzionalità costruito in gruppo con il profilo idea utente può fare quello che stai cercando.

Si prega di prendere in considerazione ciò che accade nel modello di dati quando un coordinatore viene promosso a un Principal. Non vorrei usare l'ereditarietà in questo caso a tutti. Si prega di riconsiderare la proposta del poster precedente "Combinando alla funzione integrata di gruppo con l'idea profilo utente può fare quello che stai cercando."

Avete bisogno di oggetti delle classi utente di agire come un auth.User da qualche parte? Questa sarebbe la ragione più ovvia per usare l'ereditarietà su OnetoOne. One Pro dell'approccio OnetoOne sarebbe la facilità con cui è possibile passare ad un altro modello per l'utente, se questo è un problema.

Il vero problema che vedo con quello che hai sopra (con entrambi i metodi) è che non sembra essere nulla ti impedisce di avere un oggetto principale e una quota oggetto amministratore lo stesso utente. OneToOneField può garantire solo un mapping uno-a-uno tra due relazioni.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top