Search code examples
pythondjangodjango-formsdjango-admininline-formset

Django inline formset filters in manytomany relationship through another model


I have two models SchoolClass and Student, which have a many-to-many relationship through an Enrolment model.

class Student(models.Model):
    name = models.CharField(max_length=100)
    code = models.CharField(max_length=10)

class SchoolClass(models.Model):
    code = models.CharField(max_length=100)
    cycle = models.ForeignKey(Cycle)
    students = models.ManyToManyField(Student,through='Enrolment')

class Enrolment(models.Model):
    student = models.ForeignKey(Student)
    school_class = models.ForeignKey(SchoolClass)

The SchoolClass model has a field cycle (which is the year+semester that class runs in. When I view a student in the admin, I'd like to see the classes that student is enrolled in only for a given cycle (e.g. the current cycle)

I had previously had the cycle field in the Enrolment model, and the following worked nicely:

class StudentEnrolmentsInlineFormSet(BaseInlineFormSet):
    def get_queryset(self):
        if not hasattr(self, '_queryset'):
            qs = super(StudentInlineFormSet, self).get_queryset().filter(cycle=Current)
            self._queryset = qs
        return self._queryset

class StudentEnrolmentsInline(admin.TabularInline):
    model = Enrolment
    formset = StudentEnrolmentsInlineFormSet

class StudentAdmin(admin.ModelAdmin):
    form = StudentForm
    inlines = (StudentEnrolmentsInline,)

However, I've moved the cycle in the the SchoolClass model, and now can't work out how to apply the filter through to the next model.


Solution

  • Unless I'm overlooking something, you can do this with the queryset method on StudentEnrolmentsInline:

    def queryset(self, request):
        current = Cycle.objects.latest() # or whatever to get the current cycle
        qs = super(StudentEnrolmentsInline, self).queryset(request)
        return qs.filter(school_class__cycle=current)