Django 小实例S1 简易学生选课管理系统 第11节——学生课程业务实现

点击查看教程总目录

作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师。

课程模块中,学生需要拥有的功能有:

  • 查看课程列表
  • 选课撤课
  • 结课后评教

1 - 查看课程列表

学生可以按类别view_kind查看课程,view_kind分为

  • current: 查看当前课程
  • is_end: 查看结课课程
  • select: 可选课的
  • withdraw: 可撤课的

新建学生查看课程的模板templates/course/student/home.html如下

{% extends "course/nav.html" %}
{% block title %}HomePage{% endblock %}
{% block content %}
<div class="main-container">
<div class="main-bar">
<form class="search-form" method="post">
{% csrf_token %}
<input class="input" id="search-key" type="text" name="search" {% if search_key != None %}value="{{ search_key }}" {% endif %}/>
<input class="button" type="submit" value="搜索课程" />
</form> {% if view_kind != "select"%}
<input class="button right-button" type="button" value="选课" onclick='window.open("{% url 'view_course' 'select' %}")' />
{% endif %}
{% if view_kind != "withdraw"%}
<input class="button right-button" type="button" value="撤课" onclick='window.open("{% url 'view_course' 'withdraw' %}")' />
{% endif %}
{% if view_kind != "is_end"%}
<input class="button right-button" type="button" value="查看结课课程" onclick='window.open("{% url 'view_course' 'is_end' %}")' />
{% endif %}
{% if view_kind != "current"%}
<input class="button right-button" type="button" value="查看当前课程" onclick='window.open("{% url 'view_course' 'current' %}")' />
{% endif %}
</div>
<h3>{% if view_kind == "select"%}
选课
{% elif view_kind == "withdraw"%}
撤课
{% elif view_kind == "is_end"%}
查看结课课程
{% elif view_kind == "current"%}
查看当前课程
{% endif %}</h3>
<table class="item-list course-list">
<thead>
<tr>
<th class="course-no">课程编号</th>
<th class="course-name">名称</th>
<th class="course-credit">学分</th>
{% if view_kind == "is_end" %}
<th class="course-year-semester">年份学期</th>
{% else %}
<th class="course-number">当前人数/<br>最大人数</th>
<th class="course-year">年份</th>
<th class="course-semester">学期</th>
{% endif %}
<th class="course-teacher">教师</th>
{% if view_kind == "is_end" %}
<th class="course-scores">得分</th>
<th class="course-comments">评语</th>
<th class="course-rating">学生评分</th>
<th class="course-assessment">学生评价</th>
<th class="course-operation student-course">操作</th>
{% else %}
<th class="course-schedule">上课时间</th>
<th class="course-operation student-course">操作</th>
{% endif %}
</tr>
</thead>
<tbody>
{% if view_kind == "is_end" %}
{# end course show student course #}
{% for sc in course_list %}
<tr id="course-id-{{ sc.course.id }}">
<td class="course-no">{{ sc.course.id }}</td>
<td class="course-name">{{ sc.course.name }}</td>
<td class="course-credit">{{ sc.course.credit }}</td>
<td class="course-year-semester">{{ sc.course.year }} {{ sc.course.get_semester_display }}</td>
<td class="course-teacher">{{ sc.course.teacher.name }}</td>
<td class="course-scores">{{ sc.scores }}</td>
<td class="course-comments">{{ sc.comments }}</td>
{% if sc.rating == None %}
<td class="course-rating">-</td>
<td class="course-assessment">-</td>
<td class="course-operation student-course">
<input class="button" type="button" value="查看详情" onclick='location.href="{% url 'sview_detail' sc.id%}"' />
<input class="button" type="button" value="评教"
onclick='window.open("{% url 'evaluate' sc.id %}")' />
</td>
{% else %}
<td class="course-rating">{{ sc.rating }}</td>
<td class="course-assessment">{{ sc.assessment }}</td>
<td class="course-operation student-course">
<input class="button" type="button" value="查看详情" onclick='location.href="{% url 'sview_detail' sc.id%}"' />
</td>
{% endif %}
</tr>
{% endfor %}
{% else %}
{% for course in course_list %}
<tr id="course-id-{{ course.id }}">
<td class="course-no">{{ course.id }}</td>
<td class="course-name">{{ course.name }}</td>
<td class="course-credit">{{ course.credit }}</td>
<td class="course-number">{{ course.get_current_count }}/{{ course.max_number }}</td>
<td class="course-year">{{ course.year }}</td>
<td class="course-semester">{{ course.get_semester_display }}</td>
<td class="course-teacher">{{ course.teacher.name }}</td>
<td class="course-schedule">
{% for schedule in course.get_schedules %}
<div>{{ schedule }}</div>
{% endfor %}
</td>
<td class="course-operation student-course">
{% if view_kind == "select"%}
<input class="button" type="button" value="选课"
onclick='window.open("{% url 'operate_course' course.id 'select' %}")' />
{% endif %}
{% if view_kind == "withdraw"%}
<input class="button" type="button" value="撤课"
onclick='window.open("{% url 'operate_course' course.id 'withdraw' %}")' />
{% endif %}
{% if view_kind == "current"%}
-
{% endif %}
</td>
</tr>
{% endfor %}
{% endif %}
</tbody> </table>
</div>
{% endblock %}

然后在course/views.py中添加代码如下

def view_course(request, view_kind):
"""
:param view_kind:
current: 查看当前课程
is_end: 查看结课课程
select: 选课
withdraw: 撤课
"""
user = get_user(request, "student")
if not user:
return redirect(reverse("login", kwargs={"kind": "student"})) is_search = False
search_key = ""
if request.method == "POST":
search_key = request.POST.get("search")
if search_key:
is_search = True info = {
"name": user.name,
"kind": "student",
} course_list = [] if view_kind in ["select", "current", "withdraw", "is_end"]:
if view_kind == "select":
q = Q(status=2)
if is_search:
q = q & (Q(name__icontains=search_key) | Q(teacher__name__icontains=search_key)) course_list = Course.objects.filter(q) my_course = StudentCourse.objects.filter(Q(student=user) & Q(with_draw=False))
my_cids = [c.course.id for c in my_course]
course_list = [c for c in course_list if c.id not in my_cids]
else:
q = Q(student=user) & Q(with_draw=False)
if is_search:
q = q & (Q(name__icontains=search_key) | Q(teacher__name__icontains=search_key))
my_course = StudentCourse.objects.filter(q)
if view_kind == "current":
course_list = [c.course for c in my_course if c.course.status < 4]
elif view_kind == "withdraw":
course_list = [c.course for c in my_course if c.course.status == 2]
elif view_kind == "is_end":
course_list = [c for c in my_course if c.course.status >= 4] else:
return HttpResponse(INVALID_REQUEST_METHOD) context = {
'info': info,
'view_kind': view_kind,
'course_list': course_list
}
if is_search:
context["search_key"] = search_key return render(request, 'course/student/home.html', context)

课程主页即学生的个人主页,故修改course/views.py中的原视图方法student_home为

def student_home(request):
return redirect(reverse("view_course", kwargs={"view_kind": "current"}))

2 - 选课撤课

选课是新建一个学生课程关系记录,撤课则是修改对应的学生课程关系记录。

即学生有两种操作课程方法,operate_kind如下:

  • select: 选课
  • withdraw: 撤课

如果网页请求发送的方法不在这两种里面,则不符合规范,同时需要将这一信息通过响应返回告知浏览器。

故在constants.py中添加ILLEGAL_KIND = "Illegal kind for you."

在course/views.py中,导入ILLEGAL_KIND,然后添加代码如下

# 在开头导入timezone
from django.utils import timezone def operate_course(request, operate_kind, course_id):
"""
:param operate_kind:
select: 选课
withdraw: 撤课
"""
user = get_user(request, "student")
if not user:
return redirect(reverse("login", kwargs={"kind": "student"})) if operate_kind not in ["select", "withdraw"]:
return HttpResponse(ILLEGAL_KIND)
elif operate_kind == "select":
course = Course.objects.filter(pk=course_id).get()
new_course = StudentCourse(student=user, course=course)
new_course.save()
elif operate_kind == "withdraw":
q = Q(course__id=course_id) & Q(student=user) & Q(with_draw=False)
course = StudentCourse.objects.filter(q).get()
course.with_draw = True
course.with_draw_time = timezone.now()
course.save() return redirect(reverse("view_course", kwargs={"view_kind": operate_kind}))

3 - 结课后评教

学生给老师评教和老师给学生评分的后端逻辑是一样的,都是修改学生课程关系表内的数据。

先在course/forms.py中添加

class RateForm(forms.ModelForm):
class Meta:
model = StudentCourse
fields = ["course", "scores", "comments", "rating", "assessment"] course = forms.CharField(label="课程", disabled=True)
scores = forms.IntegerField(label="成绩", disabled=True)
comments = forms.CharField(label="老师评价", disabled=True) def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.initial['course'] = self.instance.course
self.initial['scores'] = self.instance.scores
self.initial['comments'] = self.instance.comments def clean_course(self):
return self.initial['course'] def clean_scores(self):
return self.initial['scores'] def clean_comments(self):
return self.initial['comments']

然后添加模板文件templates/course/student/rating.html:

{% extends "course/nav.html" %}
{% block title %}评教{% endblock %}
{% block content %}
<h3>评教</h3>
<div class="form create-update-from">
<form method="post">
{% csrf_token %}
{{form.as_p}}
<div class="submit-button">
<input type="submit" value="确定"/>
<input type="button" value="返回" onclick='location.href="{{ return_url }}"' />
</div>
</form>
</div>
{% endblock %}

再在course/cbvs.py中导入RateForm类,然后添加代码如下

class RateUpdateView(UpdateView):
model = StudentCourse
form_class = RateForm
template_name = 'course/student/rating.html' def get(self, request, *args, **kwargs):
self.object = self.get_object() info = {}
return_url = reverse("view_course", kwargs={"view_kind": "is_end"})
if self.object:
student = self.object.student
info = {
"name": student.name,
"kind": "student",
} return self.render_to_response(self.get_context_data(info=info, return_url=return_url)) def get_success_url(self):
return reverse("view_course", kwargs={"view_kind": "is_end"})

4 - 学生课程详情页

这个使用CBVs实现起来最快

先添加模板templates/course/student/course.html如下

{% extends "course/nav.html" %}
{% block title %}课程详情{% endblock %}
{% block content %}
<h3>课程详情</h3>
<ul class="course-details">
<li class="course-detail"><span class="detail-name">课程编号</span> {{ object.course.id }}</li>
<li class="course-detail"><span class="detail-name">课程名</span> {{ object.course.name }}</li>
<li class="course-detail"><span class="detail-name">学分</span> {{ object.course.credit }}</li>
<li class="course-detail"><span class="detail-name">课程人数/最大人数</span> {{ object.course.get_current_count }}/{{ object.course.max_number }}</li>
<li class="course-detail"><span class="detail-name">年份</span> {{ object.course.year }}</li>
<li class="course-detail"><span class="detail-name">学期</span> {{ object.course.get_semester_display }}</li> <li class="course-detail"><span class="detail-name">教师</span> {{ object.course.teacher.name }}</li>
<li class="course-detail"><span class="detail-name">上课时间</span>
<span class="course-schedules">
{% for schedule in object.course.get_schedules %}
<div class="course-schedule">{{ schedule }}</div>
<div class="course-schedule">{{ schedule }}</div>
{% endfor %}
</span>
</li>
<li class="course-detail"><span class="detail-name">得分</span>
{% if object.scores != None %}{{ object.scores }}{% else %} - {% endif %}
</li>
<li class="course-detail"><span class="detail-name">评语</span>
{% if object.comments != None %}{{ object.comments }}{% else %} - {% endif %}
</li>
<li class="course-detail"><span class="detail-name">学生评分</span>
{% if object.rating != None %}{{ object.rating }}{% else %} - {% endif %}
</li>
<li class="course-detail"><span class="detail-name">学生评价</span>
{% if object.assessment != None %}{{ object.assessment }}{% else %} - {% endif %}
</li> </ul>
<input type="button" value="返回" onclick='location.href="{% url 'view_course' 'is_end'%}"' />
{% endblock %}

再在course/cbvs.py中添加代码如下

class StudentCourseDetailView(DetailView):
model = StudentCourse
template_name = 'course/student/course.html' def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
if self.object:
context["info"] = {
"name": self.object.student.name,
"kind": "student",
}
return self.render_to_response(context)

5 - 添加路由

上面已经把学生需要的视图方法全部实现完毕了,接下来就是添加到路由里面。

修改后的course/urls.py如下

from django.urls import path
from course.views import *
from course.cbvs import ScoreUpdateView, RateUpdateView, StudentCourseDetailView urlpatterns = [
path('<slug:kind>/', home, name="course"),
path('teacher/create_course', create_course, name="create_course"),
path('teacher/view_detail/<int:course_id>', view_detail, name="view_detail"),
path('teacher/create_schedule/<int:course_id>', create_schedule, name="create_schedule"),
path('teacher/delete_schedule/<int:schedule_id>', delete_schedule, name="delete_schedule"),
path('teacher/score/<int:pk>', ScoreUpdateView.as_view(), name="score"),
path('teacher/handle_course/<int:course_id>/<int:handle_kind>', handle_course, name="handle_course"), path('student/view/<slug:view_kind>', view_course, name="view_course"),
path('student/operate/<int:course_id>/<slug:operate_kind>', operate_course, name="operate_course"), path('student/evaluate/<int:pk>', RateUpdateView.as_view(), name="evaluate"),
path('student/view_detail/<int:pk>', StudentCourseDetailView.as_view(), name="sview_detail"),
]

6 - 效果

选课页面

当前课程页面

Django 小实例S1 简易学生选课管理系统 11 学生课程业务实现的更多相关文章

  1. Django 小实例S1 简易学生选课管理系统 12 CSS样式完善

    Django 小实例S1 简易学生选课管理系统 第12节--CSS样式完善 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 课程模块的逻辑代码到这里 ...

  2. Django 小实例S1 简易学生选课管理系统 10 老师课程业务实现

    Django 小实例S1 简易学生选课管理系统 第10节--老师课程业务实现 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 课程模块中,老师将要使 ...

  3. Django 小实例S1 简易学生选课管理系统 9 创建课程模型(model)

    Django 小实例S1 简易学生选课管理系统 第9节--创建课程模型(model) 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 对于课程模块, ...

  4. Django 小实例S1 简易学生选课管理系统 8 CSS样式优化

    Django 小实例S1 简易学生选课管理系统 第8节--CSS样式优化 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 前面的几节下来,用户模块基 ...

  5. Django 小实例S1 简易学生选课管理系统 7 修改个人信息

    Django 小实例S1 简易学生选课管理系统 第7节--修改个人信息 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 用户模块除了注册登录之外,还 ...

  6. Django 小实例S1 简易学生选课管理系统 6 实现登录逻辑

    Django 小实例S1 简易学生选课管理系统 第6节--实现登录逻辑 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 1 业务逻辑 本教程第四节里 ...

  7. Django 小实例S1 简易学生选课管理系统 2 新建项目(project)并进行设置

    Django 小实例S1 简易学生选课管理系统 第2节--新建项目(project)并进行设置 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 0 ...

  8. Django 小实例S1 简易学生选课管理系统 3 创建用户模型(model)

    Django 小实例S1 简易学生选课管理系统 第3节--创建用户模型(model) 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 本文涉及到的新 ...

  9. Django 小实例S1 简易学生选课管理系统 4 实现登录页面

    Django 小实例S1 简易学生选课管理系统 第4节--实现登录页面 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 本文涉及到的新的额外知识点: ...

随机推荐

  1. Hive语法及其进阶(一)

    1.Hive完整建表 1 CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name( 2 [(col_name data_type [COMMENT col ...

  2. Markdown 编写技巧汇总(一)

    编写文档,有很多格式选择,也有不同平台选择.下面就自己接触到的MarkDown编写文档的各种技巧做简单梳理,供自己参阅,也希望帮到网友. [1]添加空格 ①   这种写法比较老土,但是,很实用!注意都 ...

  3. 突破GD渲染的图片马

    <?php /* The algorithm of injecting the payload into the JPG image, which will keep unchanged aft ...

  4. 踩坑系列《十三》解决时间戳long转换int溢出(即转换值为负数)

    最近业务需求,需要使用到 int 类型的时间戳,所以在使用时间戳的时候,由于java自带的 System.currentTimeMillis() 返回的类型是long,强行转换一波的话,是会出现数据溢 ...

  5. 实现一个简单的侧边导航Winform程序框架

    目录 简介 实现导航面板 实现方法 使用方法 实现标题栏 窗体拖拽及最大化 自定义窗体按钮 标题显示 按钮设置 实现状态栏 整体使用 参考文章 简介 每次新项目都要想着界面怎么设计好,但想来想去上位机 ...

  6. Java基础之(九):循环结构

    循环结构 前面我们已经聊过了if语句,接下来我们就聊聊跟选择语句一样常用的语句:循环语句. 同样的,所有的循环语句都可以写成for语句 while循环 while循环的格式: while(布尔表达式) ...

  7. Flask聚合函数(基本聚合函数、分组聚合函数、去重聚合函数))

    Flask聚合函数 1.基本聚合函数(sun/count/max/min/avg) 使用聚合函数先导入:from sqlalchemy import func 使用方法: sun():func.sum ...

  8. 微信h5跳转小程序wx-open-launch-weapp开放标签不显示(已解决)

    前言: 前几天成功对接了跳转第三方小程序的功能,今天有个页面有需要对接.但是奇怪的是用的和上次一模一样的配置,但就是死活不显示wx-open-launch-weapp这个开放标签的按钮,看不到任何效果 ...

  9. 第四代富士X100F操作学习

    前言 本文为自己通过B站的UP主[阿布垃机手册]整理.原视频地址:[阿布垃机手册][布瞎BB]富士 X100F 相机外部按键 拍人像自己的设置 [X100F相机光圈大小支持F2到F16+Auto]光圈 ...

  10. python进阶(21)typing模块--类型提示支持

    typing介绍   Python是一门弱类型的语言,很多时候我们可能不清楚函数参数的类型或者返回值的类型,这样会导致我们在写完代码一段时间后回过头再看代码,忘记了自己写的函数需要传什么类型的参数,返 ...