Autopopulate a related table when the parent is created

I have this lesson model that is created for a class.

class Lesson(models.Model):
  id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
  lesson_code = models.CharField(choices=TOPIC_CHOICES, default='SWA01', max_length=20)
  lesson_name = models.CharField(max_length=255)
  lesson_topic = models.ForeignKey(Topic, on_delete=models.CASCADE, related_name='lessons')
  lesson_description = models.TextField()
  lesson_video = models.URLField(blank=True)
  lesson_document = models.FileField(upload_to='documents/', blank=True)

  def __str__(self):
      return self.lesson_name

I want then when a student enrolls into a class, and registers as a user, all the lessons available are re-created as Lesson Attendance using a lesson Attendance model shown:

class LessonAttendance(models.Model):
  student = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
  lesson = models.ForeignKey(Lesson, on_delete=models.CASCADE)
  teacher = models.ForeignKey(StaffUser, on_delete=models.CASCADE)
  progress = models.IntegerField(default=0)

class Meta:
    unique_together = ['student', 'lesson']

def __str__(self):
    return self.lesson.lesson_name

You haven’t shown what it means for “a student enrolls into a class” so we really can’t address what exactly you should do for this, but in general, you would create your new objects in the same place of your code where you’re performing that enrollment process.

from django.contrib.auth import get_user_model

from django.db import models

from django.contrib.auth.models import AbstractUser

from courses.models import Lesson

class CustomUser(AbstractUser):

    is_student = models.BooleanField('student', default=True)

    is_parent = models.BooleanField('parent', default=False)

    is_teacher = models.BooleanField('teacher', default=False)

    zip_code = models.CharField(max_length=100, null=True)

    profile_picture = models.ImageField(upload_to='profile_images/', default='media/wakanda_image.jpeg')

    def __str__(self):

        db_view_name = f'{self.first_name} {self.last_name}'

        return db_view_name

class StaffUser(models.Model):

    name = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)

    phone_number = models.CharField(max_length=20, blank=True)

    country = models.CharField(max_length=50, blank=True)

    bio = models.TextField(blank=True)

    def __str__(self):

        db_view_name = f'{self.name.first_name} {self.name.last_name}'

        return db_view_name

This is my custom model for a user.
so i want when a user is created LessonAttendance is created automatically in his name so i can track progress per student in each lesson.

We need to see the views / forms that you’re using that create the instances of these models. That’s where you would add in the code to create the other objects.

Hi John,

How about adding helper methods on your CustomUser class like this:

    def enroll_all(self):
        """Create Attendance for all lessons."""
        for lesson in Lesson.objects.all():
            self.lessonattendance_set.create(lesson=lesson)

Then, for a given user, you could call:

some_user.enroll_all()

where needed from your view or from wherever you are processing enrollments.

The relation between User and Lesson in your case is basically a “many-to-many” relation, so you could also look at defining it as such, see here for examples.

Hi @awtimmering ,
Thanks for your suggestion. I have not been able to implement the helper function yet. Do you by any chance a source i can look at the implementation ?

What I meant is to add that helper function to your Model, e.g. in your models.py:

class CustomUser(AbstractUser):
    def __str__(self):
        return f'{self.username}'

    def enroll_all(self):
        """Create Attendance for all lessons."""
        for lesson in Lesson.objects.all():
            self.lessonattendance_set.create(lesson=lesson)


class Lesson(models.Model):
    name = models.CharField(max_length=255)

    def __str__(self):
        return self.name


class LessonAttendance(models.Model):
    student = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
    lesson = models.ForeignKey(Lesson, on_delete=models.CASCADE)
    # teacher = models.ForeignKey(StaffUser, on_delete=models.CASCADE)
    progress = models.IntegerField(default=0)

    class Meta:
        unique_together = ('student', 'lesson', )

    def __str__(self):
        return f'{self.student} @ {self.lesson}'

Then how to call enroll_all() really depends on your application. Is there an “Enroll” button somewhere on a web page that a teacher or student clicks?
If so, then the view that processes that can call it, assuming you already have a number of Lessons in your db.

1 Like

Thanks @awtimmering your answer helped me refactor the user registration and the helper is working perfectly.