era5tone
era5tone

Reputation: 657

How to go 2 layers deep reverse relations inside django models?

I'm using a single User model for authentication and creating multiple "type" accounts using the User model. Every type has a different dashboard so different things to show.

Organization
-> Teacher
    -> Student

Q - I want to list the teachers and their corresponding students when inside a organization account ? It is a listView so I want to know how would I use revere relations to list all the students under specific teachers from an Organization account ?

class User(AbstractUser):
    ...


class Organization(models.Model):
    user_id = models.OneToOneField(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='superAdmin')
    ...

class Teacher(models.Model):
    user_id = models.OneToOneField(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='faculty')
    super_admin_id = models.ForeignKey(
        SuperAdmin, on_delete=models.CASCADE, related_name='faculty')
    ...


class Student(models.Model):
    user_id = models.OneToOneField(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='user')
    faculty_id = models.ForeignKey(
        Teacher, on_delete=models.CASCADE, related_name='student')
    ...

If there's any advice on how I can improve the existing model schema, I'd like to know that as well.

Upvotes: 0

Views: 117

Answers (1)

Brian Destura
Brian Destura

Reputation: 12068

You can fetch the teachers along with their students (in two db hits) like this:

teachers = Teacher.objects.filter(
    user_id__superAdmin=request.user.superAdmin
).prefetch_related('student')

for teacher in teachers:
    print(f'Teacher: {teacher.pk}')
    for student in teacher.student.all():
        print(f'Student: {student.pk}')

EDIT:

You can also annotate per teacher the number of students assigned to them so:

teachers = Teacher.objects.filter(
    user_id__superAdmin=request.user.superAdmin
).annotate(num_students=Count('student'))

for teacher in teachers:
    print(f'Teacher {teacher.pk} has {teacher.num_students} students')

Upvotes: 1

Related Questions