Multiple User Types with Django


(Yurii Parfonov) #1

Dear Vitor,

I’m developing a project like the “Django School” from your wonderful tutorial
“How to Implement Multiple User Types with Django”. It’s supposed to be three types of users in
my web application: superuser, teacher (staff member) and student.

I have a custom user model:

class CustomUser(AbstractUser):
    is_student = models.BooleanField(default=False, verbose_name='Student')
    is_teacher = models.BooleanField(default=False, verbose_name='Teacher')
    class Meta:
        db_table = "custom_users"

a custom student model with some extra information, related to all students:

class Student(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True)
    l_name = models.CharField(max_length=25, verbose_name='Student Last Name')
    f_name = models.CharField(max_length=25, verbose_name='Student First Name')
    m_name = models.CharField(max_length=25, verbose_name='Student Middle Name')
    year = models.PositiveSmallIntegerField(validators=[MinValueValidator(1), MaxValueValidator(6)], default=2, verbose_name='Year')
    academic_group = models.ForeignKey('AcademicGroup', verbose_name='Academic Group', on_delete=models.CASCADE)   
    class Meta:
        unique_together = ("l_name", "f_name", "m_name")
        db_table = "students"

and a form to sign up the student

class StudentSignUpForm(UserCreationForm):
    first_name = forms.CharField(max_length=30, required=True, label=_('First name'))
    middle_name = forms.CharField(max_length=30, required=True, label=_('Middle name'))
    last_name = forms.CharField(max_length=30, required=True, label=_('Last name'))
    year = forms.IntegerField(min_value=1, max_value=6, required=True, label=_('Year'))
    academic_group = forms.ModelChoiceField(queryset=AcademicGroup.objects.all().order_by('academic_group_code'),
                                            label=_('Academic group'))
    class Meta(UserCreationForm.Meta):
        model = CustomUser
        fields = ('last_name', 'first_name', 'middle_name', 'year', 'academic_group',) + UserCreationForm.Meta.fields

    @transaction.atomic
    def save(self):
        user = super().save(commit=False)
        user.is_student = True
        user.save()
        student = Student.objects.create(user=user, academic_group=self.cleaned_data.get('academic_group'))
        student.f_name = self.cleaned_data.get('first_name')
        student.m_name = self.cleaned_data.get('middle_name')
        student.l_name = self.cleaned_data.get('last_name')
        student.year = self.cleaned_data.get('year')
		#1
        student.save()
		#1
        return user

I would like to store user data (username, password, …) in the database table “custom_users” and
data related to the student (f_name, m_name, l_name, year, academic_group) in the “students” table.

However, I have some difficulties doing that.
First, if #1 statement in the StudentSignUpForm is commented, only values of “year” and “academic_group” are in the “students” table.
First Name and Last Name goes to the “custom_users” table.
Second, if the #1 statement is uncommented, all data related to the student goes to the “students”
table, and “f_name” and “l_name” - to the “custom_users” table too.

I wonder if there is something wrong with my code or I need to pick a different strategy
to implement custom user model?

Thanks in advance.