Django Multi-herencia de tabla VS Especificación OneToOne explícita la relación en modelos

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

  •  22-09-2019
  •  | 
  •  

Pregunta

Espero que todo esto tiene sentido :) Voy a aclarar a través de los comentarios si es necesario. Además, estoy experimentando el uso de texto en negrita en esta pregunta, y voy a editarlo si yo (o) parece distraer. Con eso fuera del camino ...

Usando nos da django.contrib.auth de usuario y de grupo, entre otras cosas útiles que no puedo prescindir (como la mensajería básica).

En mi aplicación tengo varios tipos diferentes de usuarios. Un usuario puede ser de un solo tipo. Eso sería fácilmente manejados por grupos, con un poco de cuidado extra. No obstante, estos diferentes usuarios se relacionan entre sí en las jerarquías / relaciones.

Vamos a echar un vistazo a estos usuarios: -

Directores - usuarios "alto nivel"

Administradores - cada uno de los informes de administrador a un principal

Coordinadores - cada coordinador informa a un Administrador

Además de estos otros tipos hay usuarios que no están relacionados directamente , pero pueden quedar relacionados más adelante. Por ejemplo, "Company" es otro tipo de usuario, y puede tener diferentes "productos", y los productos puede ser supervisado por un "coordinador". "Comprador" es otro tipo de usuario que pueden comprar productos.

Ahora todas estas los usuarios tienen varios otros atributos, algunos de los cuales son comunes a todos los tipos de usuarios y algunos de los cuales son distintos sólo para un tipo de usuario . Por ejemplo, todos los tipos de usuarios tienen que tener una dirección. Por otro lado, sólo el usuario principal pertenece a una "BranchOffice".

Otro punto, que se ha indicado anteriormente, es que un usuario puede solamente siempre ser de un tipo .

La aplicación también necesidades para realizar un seguimiento de quién creó y / o directores modificados, administradores, coordinadores, empresas, productos, etc. . (Así que por dos enlaces más al modelo de usuario.)

En este escenario, es una buena idea utilizar la herencia de varias mesas de Django de la siguiente manera: -

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 debería ir haciendo de esta manera: -

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")
    #
    #
    #

Por favor, tenga en cuenta que existen otros tipos de usuarios que se relacionan a través de las claves externas, por ejemplo: -

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

Soy consciente de que Django hace uso de una relación de uno a uno para múltiples mesas herencia detrás de las escenas. Soy sólo lo suficientemente cualificado para decidir qué es un buen enfoque más.

¿Fue útil?

Solución

Me gustaría ampliar la solución por @thornomad.

La extensión de clase User de Django directa puede causar todo tipo de problemas con los mecanismos internos django.auth. Lo que he hecho en una situación similar es precisamente lo que sugiere @thornomad - Hice mi propio modelo vinculado PerfilUsuario uno-a-uno con el modelo de usuario de Django, en la que sostuve datos de usuario adicionales y de la que he heredado modelos para diferentes tipos de los usuarios.

Algo para adaptarse a lo que usted describe:

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)

Otros consejos

Hace poco cambié a la utilización de modelos que heredan fuera de contrib.auto.models.User. Mi observación general es que, en teoría, que son grandes, pero a veces no consiguen auto-mágicamente manejado como se supone a.

Creo que su decisión con respecto a la herencia OneToOne frente se reduce a esto:

  • Quiero tener Django automáticamente hacer algo bien 95% del tiempo, y la necesidad de depurar ese otro 5%

-O -

  • ¿Quiero hacer algo manualmente mí 100% del tiempo

Si no lo ha visto, el blog de Scott Barham tiene un gran post sobre la herencia de fuera del usuario, así como la construcción de un extremo trasero a medida para asegurarse de que está siendo devuelto el objeto personalizado - Extendiendo el Django usuario

Además de interés sería el campo AutoOneToOne proporcionada por django-molesto . Es una especie de híbrido entre los dos enfoques aquí -. No hay ninguna toma de herencia lugar, pero Django se hace cargo de la creación de la OneToOneField juego si no está presente

Además, thornomad hace hacer un punto sobre la redundancia en sus modelos bien. Desde aquí se puede aplicar una clase abstracta que limpiar eso por lo que (suponiendo que estás haciendo OneToOne manual):

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)

No creo que heredaría el modelo User, en lugar utilizar un UserProfile encargo - dejando el modelo contrib.auth solo. Con el modelo UserProfile costumbre, usted puede configurar un Base modelo de perfil de usuario que puede ser una parte de todos los diferentes tipos de usuario.

Con sólo mirar rápidamente, también, me gustaría mirar cuidadosamente cualquiera de los modelos que se repiten todos los mismos campos (al igual que sus dos últimos modelos Principle y Administrator). Combinando el construido en la funcionalidad de grupo con la idea perfil de usuario puede hacer lo que busca.

Por favor, considere lo que sucede en el modelo de datos cuando un coordinador es ascendido a un director. Yo no usaría la herencia en este caso en absoluto. Por favor reconsidere la sugerencia de la crítica anterior "Combinando el construido en la funcionalidad de grupo con la idea perfil de usuario puede hacer lo que usted está buscando."

¿Necesita objetos de sus clases de usuarios para actuar como un auth.user en cualquier lugar? Esa sería la razón más obvia para utilizar la herencia sobre OneToOne. Un pro del enfoque OneToOne sería la facilidad con la que se puede cambiar a otro modelo de usuario, si eso es una preocupación.

El verdadero problema que veo con lo que tiene encima (por cualquier método) es que no parece haber nada que nos impida tener un objetivo principal y una cuota objeto del administrador del mismo usuario. OneToOneField sólo puede garantizar una asignación uno a uno entre las dos relaciones.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top