You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django开发:如何跳过未填充成绩的学期模型避免DoesNotExist错误

问题解决与优化方案

一、临时解决:避免DoesNotExist错误并显示“No Data”

当前视图中使用get()方法会在无对应成绩数据时抛出异常,可通过以下两种方式处理:

方法1:用try-except捕获异常

修改视图函数,对每个成绩查询捕获DoesNotExist异常,无数据时将变量设为None,后续在模板中判断显示内容:

from django.shortcuts import render
from .models import Students, Achievement, Grades1, Grades2
from django.core.exceptions import DoesNotExist

def users(response, int):
    s = Students.objects.get(nim=int)
    
    # 处理第一学期成绩
    try:
        sg1 = s.grades1_set.get(nim=int)
    except DoesNotExist:
        sg1 = None
    
    # 处理第二学期成绩
    try:
        sg2 = s.grades2_set.get(nim=int)
    except DoesNotExist:
        sg2 = None
    
    sa = s.achievement_set.all()
    
    # 同理处理Accounts,避免无数据报错
    try:
        sac = s.accounts_set.get(nim=int)
    except DoesNotExist:
        sac = None
    
    return render(response, 'users/user.html', {
        's': s,
        'sg1': sg1,
        'sg2': sg2,
        'sa': sa,
        'sac': sac
    })

模板user.html中添加判断逻辑:

<!-- 第一学期成绩展示 -->
<h3>第一学期成绩</h3>
{% if sg1 %}
    <p>生物:{{ sg1.biology }}</p>
    <p>数学:{{ sg1.math }}</p>
    <p>历史:{{ sg1.history }}</p>
{% else %}
    <p>No Data</p>
{% endif %}

<!-- 第二学期成绩展示 -->
<h3>第二学期成绩</h3>
{% if sg2 %}
    <p>生物:{{ sg2.biology }}</p>
    <p>数学:{{ sg2.math }}</p>
    <p>历史:{{ sg2.history }}</p>
{% else %}
    <p>No Data</p>
{% endif %}

方法2:用filter().first()替代get()

filter()返回查询集,first()会返回第一个匹配对象或None,不会抛出异常,代码更简洁:

def users(response, int):
    s = Students.objects.get(nim=int)
    sg1 = s.grades1_set.filter(nim=int).first()
    sg2 = s.grades2_set.filter(nim=int).first()
    sa = s.achievement_set.all()
    sac = s.accounts_set.filter(nim=int).first()
    
    return render(response, 'users/user.html', {
        's': s,
        'sg1': sg1,
        'sg2': sg2,
        'sa': sa,
        'sac': sac
    })

模板判断逻辑和方法1一致。

二、更优实现方案:重构成绩模型

当前每个学期单独创建模型的方式扩展性极差,后续新增学期需重复创建模型、修改视图和模板,维护成本高。建议合并为单一成绩模型,新增学期字段区分不同学期:

重构后的模型代码

from django.db import models

class Students(models.Model):
    class_ = models.CharField(max_length=6, default='no data')  # 避免和Python关键字冲突,重命名clas为class_
    nim = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=50)
    year = models.IntegerField()

    def __str__(self):
        return f"{self.nim} in class {self.class_}"

# 合并所有学期成绩为一个模型
class Grades(models.Model):
    TERM_CHOICES = [
        (1, '第一学期'),
        (2, '第二学期'),
        (3, '第三学期'),
        # 后续新增学期只需在此添加选项
    ]
    nim = models.ForeignKey(Students, on_delete=models.CASCADE)
    term = models.IntegerField(choices=TERM_CHOICES)  # 新增学期字段
    biology = models.IntegerField(default=0)
    math = models.IntegerField(default=0)
    history = models.IntegerField(default=0)

    # 确保每个学生每个学期只有一条成绩记录
    class Meta:
        unique_together = ('nim', 'term')

    def __str__(self):
        return f"{self.nim.name} 第{self.term}学期成绩:生物={self.biology} 数学={self.math} 历史={self.history}"

# 其他模型(Achievement、Accounts)保持不变,建议Accounts的passwords改为password(单数更合理)

重构后的视图代码

查询学生所有学期成绩,无需单独处理每个学期:

def users(response, int):
    s = Students.objects.get(nim=int)
    # 获取该学生所有学期的成绩,按学期排序
    grades = s.grades_set.all().order_by('term')
    sa = s.achievement_set.all()
    sac = s.accounts_set.filter(nim=int).first()
    
    # 整理为字典,方便模板按学期快速查找
    grade_dict = {g.term: g for g in grades}
    
    return render(response, 'users/user.html', {
        's': s,
        'grades': grades,
        'grade_dict': grade_dict,
        'sa': sa,
        'sac': sac
    })

重构后的模板代码

可灵活显示所有有数据的学期,或指定学期:

<!-- 显示所有有成绩的学期 -->
<h3>所有学期成绩</h3>
{% for grade in grades %}
    <h4>第{{ grade.term }}学期</h4>
    <p>生物:{{ grade.biology }}</p>
    <p>数学:{{ grade.math }}</p>
    <p>历史:{{ grade.history }}</p>
{% empty %}
    <p>No Data</p>
{% endfor %}

<!-- 指定显示第一学期成绩 -->
<h3>第一学期成绩</h3>
{% if grade_dict.1 %}
    <p>生物:{{ grade_dict.1.biology }}</p>
    <p>数学:{{ grade_dict.1.math }}</p>
    <p>历史:{{ grade_dict.1.history }}</p>
{% else %}
    <p>No Data</p>
{% endif %}

三、额外建议

  1. Accounts模型优化:不要明文存储密码,使用Django自带的AbstractUser或AbstractBaseUser处理用户认证,自动加密密码,安全性更高。
  2. 字段命名规范:避免使用Python关键字(如class),字段名尽量使用单数形式(如password替代passwords)。

内容的提问来源于stack exchange,提问作者isca_

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 20:38:16