custom user and saving user objects

Before I go any further on my project I think I need to sort out my user model. At the start of the project I implemented a Custom User as explained here but I haven’t touched it since. My project is a gradebook so there is lots of functionality/objects tied to students: classrooms, assessments, grades. So far I have Student model that is not connected to the User model.

Models

class CustomUser(AbstractUser):
    pass

    def __str__(self):
        return self.username

class Student(models.Model):
    classroom = models.ForeignKey(Classroom, on_delete=models.CASCADE)
    student_first = models.CharField(default='John', max_length=30)
    student_last = models.CharField(default='Smith', max_length=30)
    nickname = models.CharField(default='JohnS', max_length=31)
    email = models.EmailField(max_length=50)
    attend = models.BooleanField(default=True)
    do_not_pick = models.BooleanField(default=False)

    def __str__(self):
        return self.nickname

View

def addmultistudent(request, classroom_id):
    """Add multiple students at once."""
    classblock = get_object_or_404(Classroom, pk=classroom_id)
    context = {'classblock': classblock}

    if request.method == 'POST':
		#form contains one TextField with a list of names
        form = StudentInputForm(request.POST)

        if form.is_valid():
            students = form.save(commit=False)
            # save the classroom that the student belongs to
            input_list = []
            input_list = students.name_list.split('\n')
            output_list = []

            for line in input_list:
                line = line.strip('\r')
                all_names = line.split()
                num_names = len(all_names)
                if num_names == 2:
                    last = all_names[1]
                else:
                    last = ' '
                nick = all_names[0] + last[:1]
                # create the object and then add the attributes
                new_student = Student()
                new_student.student_last = last
                new_student.student_first = all_names[0]
                new_student.nickname = nick
                new_student.classroom = classblock
                new_student.email = nick + "@domain.com"
                # create the list to be bulk added
                output_list.append(new_student)
            Student.objects.bulk_create(output_list)

            form = StudentInputForm(None)
            context['form'] = form
            return render(request, "gradebook/addmultistudent.html", context)

        else:
            context['form'] = form
            return render(request, "gradebook/addmultistudent.html", context)

    else:
        form = StudentInputForm(None)
        context['form'] = form
        return render(request, "gradebook/addmultistudent.html", context)

urls

app_name = 'gradebook'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('signup/', SignUpView.as_view(), name='signup'),
    path('courses/', views.courses, name='courses'),
    path('classroom/', views.classroom, name='classroom'),
    path('studentsetup/', views.studentsetup, name='studentsetup'),
    path('classroom/<int:pk>/',
         views.ClassroomDetailView.as_view(), name='classdetail'),
    path('addmultistudent/<int:classroom_id>/',
         views.addmultistudent, name='addmultistudent'),
]

template

<form action="" method="post">
    {% csrf_token %} {{ form|crispy }}
    <div class="form-group">
        <button type="submit" class="btn btn-default">Submit</button>
    </div>
</form>

My hunch is that I should use a OneToOneField in my Student model, connected to CustomUser, as discussed in this thread. The unknown part for me is how I’m creating these student users. I have a form where a list of users are cut’n’pasted into. My view then parses the list and creates the student objects. Hopefully I can still use this.

My question is, looking at my code above does it seem reasonable to connect each student to the CustomUser with a OneToOneField? Or is there another method I should be looking at? Also, I would have to add password fields to the student model and then in the view I maybe I can generate random passwords? Or can a student user “recover” a password when they try to login?

If every “Student” needs to log on, then yes, creating a OneToOne relationship with User is appropriate.
You would need to extend your view that creates a Student to also create a User. You wouldn’t need to add a password field, that’s part of the User object. You could also remove the first name, last name, and email fields from the Student, and rely upon those fields in the User object.
Django also has a built-in facility for allowing a user to change their password, assuming their email address is associated with a User object. See Authentication Views.

1 Like