学生管理系统——Django科研成果与竞赛加分模块设计:从模型到视图的完整实现

前言

在高校学生管理系统中,综合素质评价是衡量学生全面发展的重要指标。本文将详细介绍如何使用Django框架设计并实现一个科研成果与竞赛加分模块,涵盖数据模型设计、视图函数开发、模板页面渲染等完整流程。

通过本文的学习,你将掌握:

  • Django多模型关联设计的方法与技巧
  • 审核流程的状态机实现
  • 加分统计与汇总的计算逻辑

一、需求分析与功能设计

1.1 业务场景分析

高校学生的加分项主要来源于两个方面:

  1. 科研成果:学术论文、专利、科研项目、科研获奖等
  2. 竞赛获奖:各类学科竞赛、创新创业大赛等

每项成果需要经过提交-审核-确认的流程,确保加分项的真实性和公正性。

1.2 功能模块划分

模块 功能描述 用户角色
科研成果管理 提交、查看科研成果 学生
竞赛获奖管理 提交、查看获奖记录 学生
加分总览 查看加分汇总统计 学生
科研审核 审核学生提交的科研成果 管理员
竞赛审核 审核学生提交的获奖记录 管理员

提示:合理的模块划分有助于代码的维护和扩展,建议遵循单一职责原则

二、数据模型设计

2.1 科研成果模型

首先创建ResearchAchievement模型,用于存储学生的科研成果信息。

python 复制代码
from django.db import models
from django.conf import settings

class ResearchAchievement(models.Model):
    """科研成果"""
    ACHIEVEMENT_TYPES = [
        ('paper', '学术论文'),
        ('patent', '专利'),
        ('project', '科研项目'),
        ('award', '科研获奖'),
        ('report', '研究报告'),
    ]
    
    LEVEL_CHOICES = [
        ('national', '国家级'),
        ('provincial', '省级'),
        ('municipal', '市级'),
        ('school', '校级'),
    ]
    
    student = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='research_achievements',
        verbose_name='学生'
    )
    title = models.CharField('成果名称', max_length=200)
    achievement_type = models.CharField('成果类型', max_length=20, choices=ACHIEVEMENT_TYPES)
    level = models.CharField('成果级别', max_length=20, choices=LEVEL_CHOICES)
    bonus_points = models.DecimalField('加分', max_digits=5, decimal_places=1, default=0)

模型设计的要点:

  • 外键关联 :使用ForeignKey关联用户模型,支持反向查询
  • 选项字段 :使用choices参数限制可选值,保证数据一致性
  • 精确度控制DecimalField适合存储分数,避免浮点精度问题

2.2 审核状态字段

科研成果需要经过审核流程,我们添加状态相关字段。

python 复制代码
    STATUS_CHOICES = [
        ('pending', '待审核'),
        ('approved', '已通过'),
        ('rejected', '已驳回'),
    ]
    
    status = models.CharField('状态', max_length=20, choices=STATUS_CHOICES, default='pending')
    review_comment = models.TextField('审核意见', blank=True)
    reviewer = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True, blank=True,
        related_name='reviewed_research',
        verbose_name='审核人'
    )
    review_time = models.DateTimeField('审核时间', null=True, blank=True)

状态机设计说明:

状态 可转换状态 触发条件
pending approved/rejected 管理员审核操作
approved 无终态 审核通过
rejected 无终态 审核驳回

2.3 竞赛信息模型

竞赛信息作为基础数据,需要单独建模管理。

python 复制代码
class Competition(models.Model):
    """竞赛信息"""
    name = models.CharField('竞赛名称', max_length=100)
    code = models.CharField('竞赛代码', max_length=20, unique=True)
    level = models.CharField('竞赛级别', max_length=20, choices=ResearchAchievement.LEVEL_CHOICES)
    organizer = models.CharField('主办单位', max_length=100)
    description = models.TextField('竞赛描述', blank=True)
    
    registration_start = models.DateField('报名开始时间')
    registration_end = models.DateField('报名截止时间')
    competition_date = models.DateField('比赛时间', null=True, blank=True)
    
    is_active = models.BooleanField('是否开放', default=True)

竞赛模型的设计考虑:

  • 唯一标识code字段设置unique=True,确保竞赛代码唯一
  • 时间管理:记录报名和比赛时间,便于前端展示竞赛状态
  • 开关控制is_active字段控制竞赛是否对学生可见

2.4 竞赛获奖记录模型

学生获奖记录需要关联竞赛信息和学生用户。

python 复制代码
class CompetitionRecord(models.Model):
    """竞赛获奖记录"""
    AWARD_LEVELS = [
        ('first', '一等奖'),
        ('second', '二等奖'),
        ('third', '三等奖'),
        ('excellence', '优秀奖'),
        ('participation', '参与奖'),
    ]
    
    student = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='competition_records',
        verbose_name='学生'
    )
    competition = models.ForeignKey(
        Competition,
        on_delete=models.CASCADE,
        related_name='records',
        verbose_name='竞赛'
    )
    award_level = models.CharField('获奖等级', max_length=20, choices=AWARD_LEVELS)
    award_date = models.DateField('获奖日期')
    bonus_points = models.DecimalField('加分', max_digits=5, decimal_places=1, default=0)

2.5 加分汇总模型

为了提高查询效率,设计加分汇总模型存储学生的总分统计。

python 复制代码
class BonusRecord(models.Model):
    """加分汇总记录"""
    student = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='bonus_record',
        verbose_name='学生'
    )
    
    research_points = models.DecimalField('科研加分', max_digits=6, decimal_places=1, default=0)
    competition_points = models.DecimalField('竞赛加分', max_digits=6, decimal_places=1, default=0)
    other_points = models.DecimalField('其他加分', max_digits=6, decimal_places=1, default=0)
    total_points = models.DecimalField('总加分', max_digits=6, decimal_places=1, default=0)
    
    def calculate_total(self):
        """计算总分"""
        self.total_points = self.research_points + self.competition_points + self.other_points
        self.save()
        return self.total_points

提示:使用OneToOneField建立一对一关系,确保每个学生只有一条汇总记录。

三、视图函数开发

3.1 加分总览视图

加分总览页面展示学生的加分统计和最近提交记录。

python 复制代码
from django.db.models import Sum
from .models import ResearchAchievement, CompetitionRecord, BonusRecord

@login_required
def bonus_overview(request):
    """加分总览"""
    if not request.user.is_student():
        messages.error(request, '只有学生可以查看加分')
        return redirect('dashboard:dashboard')
    
    # 获取或创建加分记录
    bonus_record, created = BonusRecord.objects.get_or_create(student=request.user)
    
    # 计算科研加分(只统计已审核通过的)
    research_points = ResearchAchievement.objects.filter(
        student=request.user, status='approved'
    ).aggregate(total=Sum('bonus_points'))['total'] or 0
    
    # 计算竞赛加分
    competition_points = CompetitionRecord.objects.filter(
        student=request.user, status='approved'
    ).aggregate(total=Sum('bonus_points'))['total'] or 0
    
    # 更新汇总记录
    bonus_record.research_points = research_points
    bonus_record.competition_points = competition_points
    bonus_record.calculate_total()
    
    return render(request, 'bonus/overview.html', {'bonus_record': bonus_record})

视图函数的关键点:

  • 权限检查 :使用is_student()方法验证用户角色
  • 聚合查询aggregate函数配合Sum实现分组求和
  • 空值处理 :使用or 0处理查询结果为None的情况

3.2 科研成果提交视图

学生提交科研成果的处理逻辑。

python 复制代码
@login_required
def research_add(request):
    """添加科研成果"""
    if not request.user.is_student():
        messages.error(request, '只有学生可以添加科研成果')
        return redirect('dashboard:dashboard')
    
    if request.method == 'POST':
        achievement = ResearchAchievement.objects.create(
            student=request.user,
            title=request.POST.get('title'),
            achievement_type=request.POST.get('achievement_type'),
            level=request.POST.get('level'),
            journal=request.POST.get('journal', ''),
            publish_date=request.POST.get('publish_date') or None,
            authors=request.POST.get('authors', ''),
            patent_number=request.POST.get('patent_number', ''),
            bonus_points=request.POST.get('bonus_points', 0),
            description=request.POST.get('description', ''),
        )
        messages.success(request, '科研成果提交成功,等待审核')
        return redirect('bonus:research_list')
    
    return render(request, 'bonus/research_form.html')

3.3 审核视图实现

管理员审核科研成果的核心逻辑。

python 复制代码
from django.utils import timezone

@login_required
def research_review(request):
    """科研成果审核(管理员)"""
    if not request.user.is_admin():
        messages.error(request, '权限不足')
        return redirect('dashboard:dashboard')
    
    achievements = ResearchAchievement.objects.filter(status='pending')
    
    if request.method == 'POST':
        achievement_id = request.POST.get('achievement_id')
        achievement = get_object_or_404(ResearchAchievement, id=achievement_id)
        action = request.POST.get('action')
        
        if action == 'approve':
            achievement.status = 'approved'
            achievement.bonus_points = request.POST.get('bonus_points', achievement.bonus_points)
        else:
            achievement.status = 'rejected'
        
        achievement.review_comment = request.POST.get('review_comment', '')
        achievement.reviewer = request.user
        achievement.review_time = timezone.now()
        achievement.save()
        
        messages.success(request, '审核完成')
        return redirect('bonus:research_review')
    
    return render(request, 'bonus/research_review.html', {'achievements': achievements})

审核流程说明:

  1. 权限验证:只有管理员可以访问审核页面
  2. 查询待审核 :过滤status='pending'的记录
  3. 状态更新:根据操作类型更新状态和加分值
  4. 记录审核信息:保存审核人、审核时间、审核意见

四、URL路由配置

4.1 路由设计

将所有加分相关路由集中在bonus应用下。

python 复制代码
# bonus/urls.py
from django.urls import path
from . import views

app_name = 'bonus'

urlpatterns = [
    # 学生功能
    path('', views.bonus_overview, name='overview'),
    path('research/', views.research_list, name='research_list'),
    path('research/add/', views.research_add, name='research_add'),
    path('competitions/', views.competition_list, name='competition_list'),
    path('my-competitions/', views.my_competitions, name='my_competitions'),
    path('competition/add/', views.competition_record_add, name='competition_record_add'),
    
    # 管理员功能
    path('research/review/', views.research_review, name='research_review'),
    path('competition/review/', views.competition_review, name='competition_review'),
]

4.2 路由命名规范

路由模式 命名示例 用途
列表页 research_list 展示多条记录
详情页 research_detail 展示单条记录详情
添加页 research_add 新增记录表单
编辑页 research_edit 修改记录表单
审核页 research_review 审核操作页面

五、模板页面实现

5.1 加分总览模板

展示加分统计卡片和最近记录列表。

html 复制代码
{% extends 'base.html' %}

{% block content %}
<!-- 加分统计卡片 -->
<div class="row g-4 mb-4">
    <div class="col-md-3">
        <div class="card stat-card">
            <div class="stat-icon bg-primary">
                <i class="bi bi-star"></i>
            </div>
            <div class="stat-content">
                <div class="stat-value">{{ bonus_record.total_points }}</div>
                <div class="stat-label">总加分</div>
            </div>
        </div>
    </div>
    <!-- 其他统计卡片... -->
</div>
{% endblock %}

5.2 科研成果表单模板

提交科研成果的表单页面。

html 复制代码
<form method="post">
    {% csrf_token %}
    
    <div class="row">
        <div class="col-md-6 mb-3">
            <label class="form-label">成果名称 <span class="text-danger">*</span></label>
            <input type="text" name="title" class="form-control" required>
        </div>
        <div class="col-md-6 mb-3">
            <label class="form-label">成果类型 <span class="text-danger">*</span></label>
            <select name="achievement_type" class="form-select" required>
                <option value="paper">学术论文</option>
                <option value="patent">专利</option>
                <option value="project">科研项目</option>
                <option value="award">科研获奖</option>
            </select>
        </div>
    </div>
    
    <button type="submit" class="btn btn-primary">提交审核</button>
</form>

5.3 审核页面模板

管理员审核科研成果的交互界面。

html 复制代码
{% for item in achievements %}
<div class="card mb-3">
    <div class="card-body">
        <h5>{{ item.title }}</h5>
        <p><strong>学生:</strong>{{ item.student.real_name }}</p>
        
        <form method="post">
            {% csrf_token %}
            <input type="hidden" name="achievement_id" value="{{ item.id }}">
            
            <div class="mb-2">
                <label>加分值</label>
                <input type="number" name="bonus_points" value="{{ item.bonus_points }}">
            </div>
            
            <div class="d-flex gap-2">
                <button type="submit" name="action" value="approve" class="btn btn-success">通过</button>
                <button type="submit" name="action" value="reject" class="btn btn-danger">驳回</button>
            </div>
        </form>
    </div>
</div>
{% endfor %}

六、Admin后台配置

6.1 注册模型到Admin

为管理员提供友好的后台管理界面。

python 复制代码
# bonus/admin.py
from django.contrib import admin
from .models import ResearchAchievement, Competition, CompetitionRecord, BonusRecord

@admin.register(ResearchAchievement)
class ResearchAchievementAdmin(admin.ModelAdmin):
    list_display = ['title', 'student', 'achievement_type', 'level', 'bonus_points', 'status']
    list_filter = ['status', 'achievement_type', 'level']
    search_fields = ['title', 'student__real_name']

@admin.register(Competition)
class CompetitionAdmin(admin.ModelAdmin):
    list_display = ['name', 'code', 'level', 'organizer', 'is_active']
    list_filter = ['level', 'is_active']
    search_fields = ['name', 'code']

6.2 Admin配置说明

配置项 作用
list_display 列表页显示的字段
list_filter 右侧过滤器字段
search_fields 搜索框可搜索的字段

七、数据库迁移

7.1 创建迁移文件

模型定义完成后,需要生成数据库迁移文件。

bash 复制代码
python manage.py makemigrations bonus
python manage.py migrate

迁移命令执行结果:

复制代码
Migrations for 'bonus':
  bonus\migrations\0001_initial.py
    - Create model Competition
    - Create model ResearchAchievement
    - Create model CompetitionRecord
    - Create model BonusRecord

7.2 迁移注意事项

提示:在执行迁移前,建议检查以下几点:

  • 确保AUTH_USER_MODEL配置正确
  • 确保外键关联的模型已存在
  • 备份现有数据库数据

八、功能测试验证

8.1 测试用例设计

测试场景 预期结果 验证点
学生提交科研 状态为pending 数据库记录正确
管理员审核通过 状态变为approved 加分计入汇总
管理员审核驳回 状态变为rejected 不计入加分
加分汇总计算 总分正确 aggregate查询正确

8.2 常见问题排查

问题 可能原因 解决方案
加分为0 未审核通过 检查status字段
外键错误 用户模型配置 检查AUTH_USER_MODEL
模板报错 字段名不匹配 检查模板变量名

总结

本文详细介绍了Django框架下科研成果与竞赛加分模块的设计与实现。从需求分析、模型设计、视图开发到模板渲染,覆盖了完整的功能开发流程。

核心设计要点回顾:

  • 模型关联:合理使用ForeignKey和OneToOneField建立关联关系
  • 状态管理:通过choices字段实现简单的状态机
  • 聚合统计:使用Django ORM的aggregate函数进行分组计算

下一篇文章将介绍如何为学生管理系统设计现代化的登录界面,实现左右分栏布局和科技感视觉效果。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!

相关推荐
njsgcs2 小时前
向量数据库处理分类任务和神经网络处理分类任务的区别
数据库·人工智能
de_wizard2 小时前
mysql查看binlog日志
数据库·mysql
EasyGBS2 小时前
告别低效巡检,国标GB28181视频分析平台EasyGBS视频质量诊断助力智慧城市安防精细化落地
数据库·音视频·智慧城市
知识分享小能手2 小时前
MongoDB入门学习教程,从入门到精通,MongoDB索引(5)
数据库·学习·mongodb
火星机器人life2 小时前
turtlebot3 Ubuntu 20.04 + ROS2 Foxy+Gazebo 11.15.1 环境下编译运行
数据库·ubuntu·mfc
zuowei28892 小时前
MySQL输入密码后闪退?
数据库·mysql·adb
tianyuanwo2 小时前
CentOS 8 部署 MySQL 数据库详尽操作手册
数据库·mysql·centos
星星也在雾里2 小时前
Dify配置PostgreSQL数据库连接详细教程
数据库
云边有个稻草人2 小时前
MySQL 监控实战:mysql_exporter 部署与远程监控实现
数据库·mysql