Reputation: 21
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:
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
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
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