How to create a form using multiple models in django?

So I am trying to make a student result management project.Where I can add students subhect grade and exam result.In the project i need to make a form where i can add marks of a subject to all the students of a grade(Class) at once.I want the look like the photo.Example Example .

I tried to create individual form for every sector and try to combaine them.But it didn't work.Now I need to know how can I make a form using many models in django

[Sorry for my Bad English ]

As far as I understand you want to create a form in Django that handles multiple models at once, well you can use ModelForm combined with inline formsets, by using inline formsets in Django, you can manage forms for multiple related models (like Student, Subject, and ExamResult) in one form. This is a clean and efficient way to manage forms for related data, and it avoids the complexity of manually creating individual forms for each record. If you want to learn more about inline formsets click here.

Let's do this step-by-step:

  1. Create four models Grade, Subject, Student, ExamResult.

    from django.db import models
    
    class Grade(models.Model):
        name = models.CharField(max_length=50)
    
    class Subject(models.Model):
        name = models.CharField(max_length=100)
    
    class Student(models.Model):
        first_name = models.CharField(max_length=100)
        last_name = models.CharField(max_length=100)
        grade = models.ForeignKey(Grade, on_delete=models.CASCADE)
    
    class ExamResult(models.Model):
        student = models.ForeignKey(Student, on_delete=models.CASCADE)
        subject = models.ForeignKey(Subject, on_delete=models.CASCADE)
        marks = models.DecimalField(max_digits=5, decimal_places=2)
    
  2. For each model, create a ModelForm which helps in generating the form fields dynamically.

    from django import forms
    from .models import ExamResult
    
    class ExamResultForm(forms.ModelForm):
        class Meta:
            model = ExamResult
            fields = ['subject', 'marks']  # Specify the fields you want in the form
    
  3. Create an inline formset for the ExamResult model.

    from django.forms import modelformset_factory
    from django.forms.models import inlineformset_factory
    from .models import Student, ExamResult, Subject
    
    def exam_result_formset(request, grade_id):
        students = Student.objects.filter(grade_id=grade_id)
        subjects = Subject.objects.all()
        formsets = []
    
        for student in students:
            for subject in subjects:
                formset = inlineformset_factory(Student, ExamResult, fields=('subject', 'marks'), extra=1)
                formset_instance = formset(queryset=ExamResult.objects.filter(student=student, subject=subject))
                formsets.append((student, subject, formset_instance))
    
        return render(request, 'exam_results_form.html', {'formsets': formsets})
    
  4. Create a template that will loop through all formsets and render them in the HTML form.

    <form method="post">
        {% csrf_token %}
        {% for student, subject, formset in formsets %}
            <h3>{{ student.first_name }} - {{ subject.name }}</h3>
            <div>
                {% for form in formset %}
                    <div>{{ form.as_p }}</div>
                {% endfor %}
            </div>
        {% endfor %}
        <button type="submit">Save Results</button>
    </form>
    
  5. When the form is submitted, you can process the data and save the results in views.py file.

    def save_exam_results(request, grade_id):
        if request.method == 'POST':
            formsets = []
            students = Student.objects.filter(grade_id=grade_id)
            subjects = Subject.objects.all()
    
            for student in students:
                for subject in subjects:
                    formset = inlineformset_factory(Student, ExamResult, fields=('subject', 'marks'), extra=1)
                    formset_instance = formset(request.POST)
                    if formset_instance.is_valid():
                        formset_instance.save()
                    else:
                        formsets.append((student, subject, formset_instance))
    
            return redirect('exam_results_list')  # Redirect to a page with results or confirmation
    

Thank you and have a good rest of your day buddy:)

Back to Top