Django 小实例S1 简易学生选课管理系统 11 学生课程业务实现
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 %}
{% if view_kind == "select"%}
选课
{% elif view_kind == "withdraw"%}
撤课
{% elif view_kind == "is_end"%}
查看结课课程
{% elif view_kind == "current"%}
查看当前课程
{% endif %}
课程编号
名称
学分
{% if view_kind == "is_end" %}
年份学期
{% else %}
当前人数/
最大人数
年份
学期
{% endif %}
教师
{% if view_kind == "is_end" %}
得分
评语
学生评分
学生评价
操作
{% else %}
上课时间
操作
{% endif %}
{% if view_kind == "is_end" %}
{# end course show student course #}
{% for sc in course_list %}
{{ sc.course.id }}
{{ sc.course.name }}
{{ sc.course.credit }}
{{ sc.course.year }} {{ sc.course.get_semester_display }}
{{ sc.course.teacher.name }}
{{ sc.scores }}
{{ sc.comments }}
{% if sc.rating == None %}
-
-
{% else %}
{{ sc.rating }}
{{ sc.assessment }}
{% endif %}
{% endfor %}
{% else %}
{% for course in course_list %}
{{ course.id }}
{{ course.name }}
{{ course.credit }}
{{ course.get_current_count }}/{{ course.max_number }}
{{ course.year }}
{{ course.get_semester_display }}
{{ course.teacher.name }}
{% for schedule in course.get_schedules %}
{{ schedule }}
{% endfor %}
{% if view_kind == "select"%}
{% endif %}
{% if view_kind == "withdraw"%}
{% endif %}
{% if view_kind == "current"%}
-
{% endif %}
{% endfor %}
{% endif %}
{% 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 %}
评教
{% 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 %}
课程详情
- 课程编号 {{ object.course.id }}
- 课程名 {{ object.course.name }}
- 学分 {{ object.course.credit }}
- 课程人数/最大人数 {{ object.course.get_current_count }}/{{ object.course.max_number }}
- 年份 {{ object.course.year }}
- 学期 {{ object.course.get_semester_display }}
- 教师 {{ object.course.teacher.name }}
- 上课时间
{% for schedule in object.course.get_schedules %}
{{ schedule }}
{{ schedule }}
{% endfor %}
- 得分
{% if object.scores != None %}{{ object.scores }}{% else %} - {% endif %}
- 评语
{% if object.comments != None %}{{ object.comments }}{% else %} - {% endif %}
- 学生评分
{% if object.rating != None %}{{ object.rating }}{% else %} - {% endif %}
- 学生评价
{% if object.assessment != None %}{{ object.assessment }}{% else %} - {% endif %}
{% 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('/', home, name="course"),
path('teacher/create_course', create_course, name="create_course"),
path('teacher/view_detail/', view_detail, name="view_detail"),
path('teacher/create_schedule/', create_schedule, name="create_schedule"),
path('teacher/delete_schedule/', delete_schedule, name="delete_schedule"),
path('teacher/score/', ScoreUpdateView.as_view(), name="score"),
path('teacher/handle_course//', handle_course, name="handle_course"),
path('student/view/', view_course, name="view_course"),
path('student/operate//', operate_course, name="operate_course"),
path('student/evaluate/', RateUpdateView.as_view(), name="evaluate"),
path('student/view_detail/', StudentCourseDetailView.as_view(), name="sview_detail"),
]
6 - 效果
选课页面
当前课程页面