Django Multi-Table Inheritance VS Specifying Explicit OneToOne Relationship in Models Django Multi-Table Inheritance VS Specifying Explicit OneToOne Relationship in Models django django

Django Multi-Table Inheritance VS Specifying Explicit OneToOne Relationship in Models


I'd like to expand on the solution by @thornomad.

Extending Django's User class directly can cause all kinds of trouble with the internal django.auth mechanisms. What I've done in a similar situation is precisely what @thornomad suggests - I made my own UserProfile model linked one-to-one with the Django User model, in which I held additional user data and from which I inherited models for different types of users.

Something to fit what you described:

class UserProfile(models.Model):    user = models.OneToOneField(User, blank=True, related_name='profile')    class Meta:        abstract = Trueclass 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)


I recently switched over to using models that inherit off of contrib.auto.models.User. My general observation is that in theory they're great, but sometimes they don't get auto-magically handled like they're supposed to.

I think your decision regarding inheritance vs. OneToOne comes down to this:

  • Do I want to have Django automatically do something right 95% of the time, and need to debug that other 5%

-OR-

  • Do I want to do something manually myself 100% of the time

If you haven't seen it, the Scott Barham blog has a great post about inheriting off of User, and also building a custom back end to make sure that your custom object is being returned -- Extending the Django User.

Additionally of interest would be the AutoOneToOne field provided by django-annoying. It's sort of a hybrid of the two approaches here -- there's no inheritance taking place, but Django is taking care of creating the matching OneToOneField if it's not present.

Also, thornomad does make a good point about the redundancy in your models. You could easily implement an abstract class to clean that up as so (assuming you're doing manual OneToOne):

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 = Trueclass Administrator(BaseExtendedUser):    province = models.ForeignKey(Province)class Principal(BaseExtendedUser):    branchoffice = models.ForeignKey(BranchOffice)


I don't think I would inherit the User model, rather use a custom UserProfile - leaving the contrib.auth model alone. With the custom UserProfile model, you could setup a base user profile model that can be a part of all your different user types.

Just looking at it quickly, too, I would look carefully at any models that repeat all the same fields (like your last two Principle and Administrator models). Combining the built in group functionality with the user profile idea may do what you are looking for.