Search code examples
pythondjangodjango-modelsdjango-users

Multiple types of User with many mutual attributes


How to create two User types with many mutual attributes? As far as I know, the best practise for creating two types of User is to create 2 UserProfiles. I have types - Firm and Person. So I've decided to create two UserProfiles:

class FirmProfile(models.Model):
    user = models.OneToOneField(User, related_name='firmprofile')
    prefered_times = ...
    favourite_food = ...

class PersonProfile(models.Model):
    user = models.OneToOneField(User, related_name='personprofile')
    prefered_times = ...
    favourite_food = ...

Now, I'm looking for a way I don't have to write those attributes twice. Is it possible?

EDIT: I've created this but I'm not sure if it's the best option because each UserProfile would have both profiles - firm and person

class UserProfile(User):
    user = models.OneToOneField(User, related_name='userprofile')

    TYPE_OF_USER_CHOICES = (('firm','Firm'),
                            'person','Person')

    type_of_user = models.CharField(max_length=40, choices=TYPE_OF_USER_CHOICES)

class FirmProfile(models.Model):
    user = models.OneToOneField(User, related_name='firmprofile')

class PersonProfile(models.Model):
    user = models.OneToOneField(User, related_name='personprofile')

Solution

  • There are many ways to do this https://docs.djangoproject.com/en/1.9/topics/db/models/#model-inheritance

    Simplest would be creating abstract model

    class BaseProfile(models.Model):
        prefered_times = ...
        favourite_food = ...
    
        class Meta:
            abstract = True
    
    class FirmProfile(BaseProfile):
        user = models.OneToOneField(User, related_name='firmprofile')
        ... # all custom fields can be defined here
    
    class PersonProfile(BaseProfile):
        user = models.OneToOneField(User, related_name='personprofile')
        ...
    

    Answering comment You can check type of user like this

    def get_user_type(user):
        if getattr(user, 'firmprofile', None):
            return 'firm'
        elif getattr(user, 'personprofile', None):
            return 'person'
        else:
            return None