Search code examples
djangodjango-modelsforeign-keysmany-to-manydjango-orm

How to see objects of manytomany field by related_name in admin page?


I have these two models:

class User(AbstractUser):
    is_teacher = models.BooleanField(default=False, null=False)
class Course(models.Model):
    teacher = models.ForeignKey(User, on_delete=models.CASCADE, related_name='teacher_courses')
    students = models.ManyToManyField(User, blank=True, related_name='student_courses')

Course model has a ManyToMany field and a ForeignKey to User model. In django's admin page, you are able to see a course's student/teacher. Is there a way to make it as you can have a list of a user's courses in admin page to see/add/remove courses for a user?


Solution

  • You can define a callable on your ModelAdmin class and add it to list_display. To make the courses editable on an user's page use sub classes of InlineModelAdmin.

    class TeacherCourseInlineAdmin(admin.TabularInline):
         model = Course
         fk_name = "teacher"
         
    
    class StudentCourseInlineAdmin(admin.TabularInline):
         model = Course
         fk_name = "student"
    
    
    class UserAdmin(admin.ModelAdmin):
        list_display = ("username", "teacher_courses")
        inlines = [TeacherCourseInlineAdmin, StudentCourseInlineAdmin]
    
         def get_queryset(self, *args, **kwargs):
             return super().get_queryset(*args, **kwargs).prefetch_related("teacher_courses")
    
         @admin.display(description='Courses')
         def teacher_courses(self, user):
             return [c.name for c in user.teacher_courses.all()] 
    

    Note that it makes sense to override ModelAdmin.get_queryset() to add a call to prefetch_related() so that Django fetches all related courses in one extra query instead of performing one additional query for every user object.