0

I have a website where there are two kinds of users (say) : students and tutors.

Both types have common login functionality, age, gender etc but have distinct attributes such as report cards for students and degree certificates for tutors.

I read this question : Django - Multiple User Profiles and setup my profiles as shown below:

class UserProfile(models.Model):
    user = models.OneToOneField(User, primary_key=True, related_name='profile')
    mobile = models.CharField(max_length=10, blank=False, null=True)
    picture = models.ImageField(
        upload_to='images/', default='images/newuser.png')
    age = models.IntegerField(null=True)
    slug = models.SlugField()
    ...

And two other models that link to the above. Eg:

class StudentProfile(models.Model):
    profile = models.ForeignKey(UserProfile, related_name="user_profile")
    #more custom attributes

class TutorProfile(models.Model):
   profile = models.ForeignKey(UserProfile, related_name="doctor_profile")
   #more custom attributes

Now my questions:

1) SlugField is defined on the UserProfile attribute but will ideally use the User.username field. This means a join between these two tables will happen each time. Is this to be expected?

2) Assuming I am using class based views, editing/viewing the profile will depend on the UserProfile in question. But I want the user to be able to edit/view all his details on the same page. Thus, I will have to fetch TutorProfile / StudentProfile too and add custom logic to ensure updates happen to them too.

It seems to me that there should be a proper way of handling these situations (Since a lot of websites have similar requirements). What are the best practices to be followed in such a situation?

Community
  • 1
  • 1
sudshekhar
  • 1,576
  • 3
  • 18
  • 31

1 Answers1

2

While searching for answers, I came across a solution which I think might suit my needs (posting here to welcome critique and help out others who might be looking for answers).

Taken from Django Design patterns and Best Practices

class UserProfile(models.Model):
    user = models.OneToOneField(User, primary_key=True, related_name='profile')
    mobile = models.CharField(max_length=10, blank=False, null=True)
    picture = models.ImageField(
        upload_to='images/', default='images/newuser.png')
    age = models.IntegerField(null=True)
    gender = models.IntegerField(null=True)
    user_type = models.CharField(max_length=20, choices=UserTypes.CHOICES)
    slg = models.SlugField()    

    class Meta(object):
        abstract = True


class StudentProfile(models.Model):
    report_card = models.FileField(upload_to="/temp")
    house = models.CharField()

    class Meta(object):
      abstract = True


class TutorProfile(models.Model):
    performance = models.IntegerField(default=0)
    salary = models.IntegerField(default=0)

    class Meta(object):
      abstract = True

One base abstract class and two specific classes which cover the various user profiles. Keeping them separate like this makes it easy for us to reason about the various fields present in each user type. Finally,

 class Profile(UserProfile, StudentProfile, TutorProfile):
     pass

This is the model used as the settings.AUTH_USER_MODEL.

Overall, the advantages I see:

  1. Single DB call on user edit/view page.
  2. Easier to think about overall.

Disadvantage : Lots of wasted space.

Anyone has any better suggestions?

sudshekhar
  • 1,576
  • 3
  • 18
  • 31