through queryset one objects many django inheritance multi-table

queryset - reverse many to one django



Herencia de múltiples tablas Django VS que especifica una relación explícita de OneToOne en los modelos (5)

Espero que todo esto tenga sentido :) Lo aclararé mediante comentarios si es necesario. Además, estoy experimentando con el uso de texto en negrita en esta pregunta, y lo editaré si yo (o usted) lo encuentro molesto. Con eso fuera del camino ...

Usar django.contrib.auth nos da User and Group, entre otras cosas útiles de las que no puedo prescindir (como los mensajes básicos).

En mi aplicación tengo varios tipos diferentes de usuarios. Un usuario puede ser de un solo tipo. Eso sería manejado fácilmente por grupos, con un poco de cuidado extra. Sin embargo, estos diferentes usuarios están relacionados entre sí en jerarquías / relaciones.

Echemos un vistazo a estos usuarios:

Principales - usuarios de "alto nivel"

Administradores: cada administrador informa a un director

Coordinadores: cada coordinador informa a un administrador

Además de estos, hay otros tipos de usuarios que no están directamente relacionados , pero que pueden relacionarse más adelante. Por ejemplo, "Compañía" es otro tipo de usuario, y puede tener varios "Productos", y los productos pueden ser supervisados ​​por un "Coordinador". "Comprador" es otro tipo de usuario que puede comprar productos.

Ahora, todos estos usuarios tienen otros atributos, algunos de los cuales son comunes a todos los tipos de usuarios y otros solo son distintos para un tipo de usuario . Por ejemplo, todos los tipos de usuarios deben tener una dirección. Por otro lado, solo el usuario Principal pertenece a una "Oficina Delegada".

Otro punto, mencionado anteriormente, es que un usuario solo puede ser de un tipo .

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

En este escenario, ¿es una buena idea usar la herencia de mesas múltiples 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 hacerlo 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") # # #

Tenga en cuenta que hay otros tipos de usuarios que están relacionados a través de 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 utiliza una relación uno a uno para la herencia de mesas múltiples detrás de las escenas. Simplemente no estoy lo suficientemente calificado para decidir cuál es un enfoque más sólido.


No creo que herede el modelo de User , sino que use un contrib.auth User personalizado, dejando solo el modelo contrib.auth . Con el modelo de perfil de usuario personalizado, puede configurar un modelo de perfil de usuario básico que puede ser parte de todos sus diferentes tipos de usuario.

Solo mirándolo rápidamente, también, miraría cuidadosamente cualquier modelo que repita todos los mismos campos (como sus dos últimos modelos de Principle y Administrator ). La combinación de la funcionalidad integrada del grupo con la idea del perfil del usuario puede hacer lo que está buscando.


Por favor, considere lo que sucede en el modelo de datos cuando un Coordinador es promovido a un Director. No usaría la herencia en este caso en absoluto. Reconsidere la sugerencia del póster anterior "Combinar la funcionalidad integrada del grupo con la idea del perfil del usuario puede hacer lo que está buscando".


¿Necesita objetos de sus clases de usuario para actuar como un auth.User en cualquier lugar? Esa sería la razón más obvia para usar la herencia sobre OneToOne. Uno de los profesionales del enfoque de OneToOne sería la facilidad con la que puede cambiar a otro modelo de Usuario, si eso le preocupa.

El verdadero problema que veo con lo que tienes arriba (por cualquiera de los métodos) es que no parece haber nada que te impida tener un objeto Principal y un objeto de Administrador comparten el mismo Usuario. OneToOneField solo puede garantizar un mapeo uno a uno entre dos relaciones cualquiera.


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

La extensión de la clase de Usuario de Django directamente puede causar todo tipo de problemas con los mecanismos django.auth internos. Lo que hice en una situación similar es precisamente lo que sugiere @thornomad: hice mi propio modelo de perfil de usuario vinculado uno a uno con el modelo de usuario Django, en el que tenía datos adicionales del usuario y de los cuales heredé modelos para diferentes tipos de usuarios.

Algo para adaptarse a lo que describes:

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)


Recientemente cambié a usar modelos que heredan de contrib.auto.models.User. Mi observación general es que en teoría son geniales, pero a veces no se manejan de manera automática como se supone que deben hacerlo.

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

  • ¿Quiero que Django haga algo correcto automáticamente el 95% del tiempo y necesite depurar ese otro 5%?

-O-

  • ¿Quiero hacer algo manualmente yo mismo el 100% del tiempo?

Si no lo ha visto, el blog de Scott Barham tiene una excelente publicación sobre la herencia de User, y también la construcción de un back-end personalizado para asegurarse de que su objeto personalizado sea devuelto. Extendiendo al usuario de Django .

Adicionalmente de interés sería el campo AutoOneToOne provisto por django-annoying . Es una especie de híbrido de los dos enfoques aquí: no hay herencia, pero Django se está ocupando de crear OneToOneField correspondiente si no está presente.

Además, thornomad tiene un buen punto acerca de la redundancia en sus modelos. Podría implementar fácilmente una clase abstracta para limpiar eso como tal (suponiendo que esté haciendo OneToOne manualmente):

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)