Extending ManyToManyField In Templates

Viewed 81

I need to create a manytomany field that has some options and then next to each option there is an extra field
My models:

class Subject(models.Model):
    name = models.CharField(max_length=30)
    duration = models.IntegerField()
    price = models.IntegerField()

class Student(models.Model):
    firstname = models.CharField(max_length=30)
    lastname = models.CharField(max_length=30)
    subject = models.ManyToManyField(Subject,through="StudentSubject")

class StudentSubject(models.Model)
    student = models.ForeignKey(Student,on_delete=models.CASCADE)
    subject = models.ForeignKey(Subject,on_delete=models.CASCADE)
    discount = models.IntegerField()

I used the intermediate model StudentSubject(this contains the extra field) but I'm not sure how I should render this in a template I want to do something like this:

Math DiscountField1
Physics DiscountField2
CompSci DiscountField3
2 Answers

You can enumerate over the StudentSubject so for a student you can have:

{% for studentsubject in mystudent.studentsubject_set.all %}
    {{ studentsubject.subject.name }} {{ studentsubject.discount }}
{% endfor %}

with mystudent, the student for which you list the subjects with the corresponding discount.

You can boost efficiency by prefetching and selecting the related objects in the view, so:

from django.db.models import Prefetch
from django.shortcuts import render

def my_view(request, pk):
    qs = Student.objects.prefetch_related(
        Prefetch(
            'studentsubject_set',
            queryset=StudentSubject.objects.select_related('subject')
        )
    )
    mystudent = get_object_or_404(qs, pk=pk)
    # …
    return render(request, 'some-template.html', {'mystudent': mystudent})

You can pass the intermediate model to the context:

context['student_subjects'] = StudentSubject.objects.select_related('subject').all()

Then in the template:

{% for s in student_subjects %}
    {{ s.subject.name }} {{ s.discount }}
{% endfor %}
Related