CORSICANA
CORSICANA

Reputation: 21

Prefill a list of field with value in a form

I'm developing a School Management System for my thesis and I've been stuck at implementing a grading module for 3 weeks now, I have gotten close to achieving my wanted result. I can now list all the students on a page depending on a selected subject and a field where the faculty can input a grade beside the student's name. The problem is the fields are not prefilled with the grades added to the database for students, it also creates a new object whenever I input a value rather than updating the grade if it's for the same student and same subject within the same quarter and academic year. Current Output:

Desired Output:

This is the view responsible for adding grade

def add_gradebook_for(request, id):
    global student, s
    current_year = AcademicYear.objects.get(active=True)
    current_quarter = Quarter.objects.get(active=True)
    if request.method == 'GET':
        subjects = Subject.objects.filter(faculty_id=request.user.id)
        subject = Subject.objects.get(pk=id)
        students = Students.objects.filter(section__subject_section__in=[subject])
        context = {
            "subjects": subjects,
            "subject": subject,
            "students": students,
        }
        return render(request, 'grading/add_gradebook_for.html', context)

    if request.method == 'POST':
        ids = ()
        data = request.POST.copy()
        data.pop('csrfmiddlewaretoken', None)
        subject = Subject.objects.get(pk=id)
        for key in data.keys():
            ids = ids + (str(key),)
        for s in range(0, len(ids)):
            student = Students.objects.get(id=ids[s])
            score = data.getlist(ids[s])
            total_grade = score[0]
            obj = Students.objects.get(id=ids[s])
            obj.total_grade = total_grade
            try:
                a = Gradebook.objects.get(student=student, subject=subject, total_grade=total_grade, academic_year=current_year, quarter=current_quarter)
                a.total_grade = total_grade
                a.subject = subject
                a.save()
            except:
                Gradebook.objects.update_or_create(student=student, subject=subject, total_grade=total_grade, academic_year=current_year, quarter=current_quarter)
        messages.success(request, "Grades Successfully Recorded!")
        return HttpResponseRedirect(reverse_lazy('add_gradebook_for', kwargs={'id': id}))

Html Template (irrelevant parts omitted) :

<div class="card-body">
        <div id="table" class="table-editable">

          <table class="table table-bordered table-responsive-md table-striped text-center">
            <tr>
              <th class="text-center">Student</th>
              <th class="text-center">Grade</th>
            </tr>
            {% for student in students %}
            <tr>
              <td class="pt-3-half" name="{{ student.id }}">
                    {{ student.first_Name }} {{ student.last_Name }}
              </td>
              <td class="pt-3-half">
                <input id="total_grade" class="score" type="number" name="{{ student.id }}" value="{{ student.total_grade }}">
              </td>
            </tr>
            {% endfor %}
          </table>
        </div>
      </div>

Models (irrelevant fields omitted):

class Gradebook(models.Model):
    subject = models.ForeignKey(Subject, on_delete=models.CASCADE)
    student = models.ForeignKey(Students, on_delete=models.CASCADE)
    total_grade = models.FloatField(blank=True, null=True, default=0, max_length=5)
    academic_year = models.ForeignKey(AcademicYear, on_delete=models.CASCADE)
    quarter = models.ForeignKey(Quarter, on_delete=models.CASCADE)

class Subject(models.Model):
    section = models.ForeignKey(Section, on_delete=models.CASCADE)
    name = models.CharField(max_length=255)
    faculty = models.ForeignKey(AUTH_USER_MODEL, on_delete=models.CASCADE)

class Section(models.Model):
    level = models.ForeignKey(Level, null=True, on_delete=models.CASCADE)
    section = models.CharField(max_length=15)


class Students(models.Model):
    name = models.CharField(max_length=50)
    section = models.ForeignKey(Section, on_delete=models.CASCADE)

Upvotes: 1

Views: 70

Answers (2)

CORSICANA
CORSICANA

Reputation: 21

Regarding the issue where the record is getting created rather than being updated if the student already has a grade in the subject, i fixed it by using django's update_or_create function

def add_gradebook_for(request, id):
    global student, s
    current_year = AcademicYear.objects.get(active=True)
    current_quarter = Quarter.objects.get(active=True)
    if request.method == 'GET':
        subjects = Subject.objects.filter(faculty_id=request.user.id)
        subject = Subject.objects.get(pk=id)
        students = Students.objects.filter(section__subject_section__in=[subject])
        grades = Gradebook.objects.filter(subject_id=subject)
        context = {
            "subjects": subjects,
            "subject": subject,
            "students": students,
            "grades": grades
        }
        return render(request, 'grading/add_gradebook_for.html', context)

    if request.method == 'POST':
        ids = ()
        data = request.POST.copy()
        data.pop('csrfmiddlewaretoken', None)
        subject = Subject.objects.get(pk=id)
        for key in data.keys():
            ids = ids + (str(key),)  # gather all the students id in a tuple
        for s in range(0, len(ids)):
            student = Students.objects.get(id=ids[s])
            score = data.getlist(ids[s]) # get list of score for current student in the loop
            total_grade = score[0]
            obj = Students.objects.get(id=ids[s])
            obj.total_grade = total_grade
            Gradebook.objects.update_or_create(student=student, subject=subject, academic_year=current_year, quarter=current_quarter, defaults={'total_grade':total_grade})
        messages.success(request, "Grades Successfully Recorded!")
        return HttpResponseRedirect(reverse_lazy('add_gradebook_for', kwargs={'id': id}))
    

Upvotes: 1

haduki
haduki

Reputation: 938

For the value part just try omitting the "":

value = {{ student.total_grade }}

As for the form part, you should try debugging your try block. In your code you use

 obj = Students.objects.get(id=ids[s])
 obj.total_grade = total_grade

but it seems that Gradebook object has .total_grade and not Students. Overall the best approach is to create a dedicated model form and pass the corresponding instance there:

book = Gradebook.objects.get(...)
form = GradeBookForm(instance=book)
# change total_grade and whatever else you need to.
form.save()

For more information on how to create a ModelForm check here . Also I personally add csrf token on the frontend with djangos template tag {% csrf_token %}. You can read about it here

Upvotes: 0

Related Questions