Django创建ExamGrade时更新StudentCourses的show字段报错求助
问题场景
在Django项目中定义了StudentCourses、ExamGrade、Students等模型,需求是创建ExamGrade记录时,将关联的StudentCourses模型的show布尔字段更新为True,但执行代码时出现错误:'RelatedManager' object has no attribute 'show'。
模型代码(models.py)
class StudentCourses(models.Model): id = models.AutoField(primary_key=True) student = models.ForeignKey(Students, related_name='studentcourses') studentcourse = models.ForeignKey(Courses, related_name='studentcourses', null=True) show = models.BooleanField(default=False) class ExamGrade(models.Model): id = models.AutoField(primary_key=True) lecturer = models.ForeignKey(Lecturers, null=True, related_name='examgrades') student = models.ForeignKey(StudentCourses, related_name='examgrades') class Students(models.Model): id = models.AutoField(primary_key=True) admin = models.OneToOneField(CustomUser, on_delete=models.CASCADE, related_name="students") profile_pic = models.ImageField(default='default.jpg', upload_to='uploads/student') middle_name = models.CharField(max_length=255) gender = models.CharField(max_length=255) status = models.CharField(max_length=255, null=True) country = models.CharField(max_length=255, default=None, null=True, blank=True) state = models.CharField(max_length=255, default=None, null=True, blank=True) local = models.CharField(max_length=255, default=None, null=True, blank=True) school = models.ForeignKey(School, null=True, on_delete=models.CASCADE) dob = models.CharField(max_length=100, default=None, blank=True, null=True) guardian_name = models.CharField(max_length=11, null=True) mobile = models.CharField(max_length=12, null=True, default=None) faculty = models.ForeignKey(Faculty, null=True, blank=True, on_delete=models.CASCADE) department = models.ForeignKey(Department, null=True, blank=True, on_delete=models.CASCADE) level = models.ForeignKey(Level, null=True, blank=True, on_delete=models.CASCADE) semester = models.ForeignKey('Semester', null=True, blank=True, on_delete=models.CASCADE) session = models.ForeignKey(SessionYearModel, null=True, blank=True, on_delete=models.CASCADE) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now_add=True) @property def examgrades(self): return self.examgrades_set.all().order_by('student') @property def studentcourses(self): return self.studentcourses_set.all().order_by('studentcourse')
视图代码(Views.py)
class CreateGradeView(View): def get(self, request, *args, **kwargs): lecturer= Lecturers.objects.get(admin=request.user) course = LecturerCourse.objects.filter(lecturer=lecturer) context = { 'course':course, 'room_name': "broadcast" } return render(request, 'superadmin/lecturer/add-grade.html',context) def post(self, request, *args, **kwargs): lecturer = request.POST.get('lecturer') lecturer = Lecturers.objects.get(admin=lecturer) student = request.POST.get('student') student = StudentCourses.objects.get(id=student) course = request.POST.get('lecturercourse') course = LecturerCourse.objects.get(id=course) ca_1 = request.POST.get('ca_1') ca_2 = request.POST.get('ca_2') ca_3 = request.POST.get('ca_3') exam = request.POST.get('exam') if ExamGrade.objects.filter(lecturer=lecturer, student=student, lecturercourse=course, status=True).exists(): messages.warning(request, "User Exam Score already marked") return redirect('emisapp:add-grade') try: examgrades = ExamGrade(lecturer=lecturer, student=student, lecturercourse=course, ca_1=ca_1,ca_2=ca_2,ca_3=ca_3,exam=exam, status=True) print(examgrades.student.show) examgrades.student.show = True print(examgrades.student.show) examgrades.save() messages.success(request, 'Weldone you just saved Exam Score for the day') return redirect('emisapp:add-grade') except: messages.error(request, 'There is an saving to database') return redirect('emisapp:add-grade')
AJAX代码(ajax.py)
def load_student_for_attendance_by_courses(request): studentcourse = request.GET.get('studentcourse') student = StudentCourses.objects.filter(studentcourse=studentcourse, show=False).order_by('student') return render(request, 'superadmin/settings/load-student-dropdown.html', {'student':student})
模板代码(load-student-dropdown.html)
<option value="">--Select a Student--</option> {% for s in student %} <option value="{{s.id}}">{{ s.student.admin.username }} - {{ s.student.admin.last_name }} {{ s.student.middle_name }} {{ s.student.admin.first_name }}</option> {% endfor %}
错误原因
- 重名冲突:
Students模型中定义的@property方法(examgrades、studentcourses)与Django自动生成的反向关联管理器重名,导致模型关联访问逻辑混乱,出现将RelatedManager(查询集管理器)当成单个实例访问属性的情况。 - 未单独保存关联实例:修改
StudentCourses的show字段后,仅保存了ExamGrade实例,未对StudentCourses实例执行保存操作,即使逻辑正确也无法持久化修改。
修复方案
1. 重命名冲突的@property方法
修改Students模型中的@property方法名,避免覆盖Django自动生成的反向关联管理器:
class Students(models.Model): # 其他字段保持不变 @property def related_examgrades(self): return self.examgrades.all().order_by('student') @property def related_studentcourses(self): return self.studentcourses.all().order_by('studentcourse')
2. 正确保存关联实例
修改视图中post方法的try块,单独保存StudentCourses实例:
try: # 先保存ExamGrade实例 examgrades = ExamGrade(lecturer=lecturer, student=student, lecturercourse=course, ca_1=ca_1,ca_2=ca_2,ca_3=ca_3,exam=exam, status=True) examgrades.save() # 更新并保存StudentCourses实例 student.show = True student.save() messages.success(request, '已成功保存考试成绩') return redirect('emisapp:add-grade') except Exception as e: messages.error(request, f'保存失败:{str(e)}') return redirect('emisapp:add-grade')
3. 优化字段名(可选)
为避免模型关联混淆,建议修改ExamGrade的student字段名为student_course,明确关联的是StudentCourses实例:
class ExamGrade(models.Model): id = models.AutoField(primary_key=True) lecturer = models.ForeignKey(Lecturers, null=True, related_name='examgrades', on_delete=models.SET_NULL) student_course = models.ForeignKey(StudentCourses, related_name='examgrades', on_delete=models.CASCADE) # 其他字段保持不变
对应视图代码同步修改:
examgrades = ExamGrade(lecturer=lecturer, student_course=student, lecturercourse=course, ca_1=ca_1,ca_2=ca_2,ca_3=ca_3,exam=exam, status=True)
内容的提问来源于stack exchange,提问作者Deji Peter
相关产品推荐
相关产品推荐

