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

点击查看教程总目录

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

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

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

1 - 查看课程列表

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

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

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

  1. {% extends "course/nav.html" %}
  2. {% block title %}HomePage{% endblock %}
  3. {% block content %}
  4. <div class="main-container">
  5. <div class="main-bar">
  6. <form class="search-form" method="post">
  7. {% csrf_token %}
  8. <input class="input" id="search-key" type="text" name="search" {% if search_key != None %}value="{{ search_key }}" {% endif %}/>
  9. <input class="button" type="submit" value="搜索课程" />
  10. </form>
  11. {% if view_kind != "select"%}
  12. <input class="button right-button" type="button" value="选课" onclick='window.open("{% url 'view_course' 'select' %}")' />
  13. {% endif %}
  14. {% if view_kind != "withdraw"%}
  15. <input class="button right-button" type="button" value="撤课" onclick='window.open("{% url 'view_course' 'withdraw' %}")' />
  16. {% endif %}
  17. {% if view_kind != "is_end"%}
  18. <input class="button right-button" type="button" value="查看结课课程" onclick='window.open("{% url 'view_course' 'is_end' %}")' />
  19. {% endif %}
  20. {% if view_kind != "current"%}
  21. <input class="button right-button" type="button" value="查看当前课程" onclick='window.open("{% url 'view_course' 'current' %}")' />
  22. {% endif %}
  23. </div>
  24. <h3>{% if view_kind == "select"%}
  25. 选课
  26. {% elif view_kind == "withdraw"%}
  27. 撤课
  28. {% elif view_kind == "is_end"%}
  29. 查看结课课程
  30. {% elif view_kind == "current"%}
  31. 查看当前课程
  32. {% endif %}</h3>
  33. <table class="item-list course-list">
  34. <thead>
  35. <tr>
  36. <th class="course-no">课程编号</th>
  37. <th class="course-name">名称</th>
  38. <th class="course-credit">学分</th>
  39. {% if view_kind == "is_end" %}
  40. <th class="course-year-semester">年份学期</th>
  41. {% else %}
  42. <th class="course-number">当前人数/<br>最大人数</th>
  43. <th class="course-year">年份</th>
  44. <th class="course-semester">学期</th>
  45. {% endif %}
  46. <th class="course-teacher">教师</th>
  47. {% if view_kind == "is_end" %}
  48. <th class="course-scores">得分</th>
  49. <th class="course-comments">评语</th>
  50. <th class="course-rating">学生评分</th>
  51. <th class="course-assessment">学生评价</th>
  52. <th class="course-operation student-course">操作</th>
  53. {% else %}
  54. <th class="course-schedule">上课时间</th>
  55. <th class="course-operation student-course">操作</th>
  56. {% endif %}
  57. </tr>
  58. </thead>
  59. <tbody>
  60. {% if view_kind == "is_end" %}
  61. {# end course show student course #}
  62. {% for sc in course_list %}
  63. <tr id="course-id-{{ sc.course.id }}">
  64. <td class="course-no">{{ sc.course.id }}</td>
  65. <td class="course-name">{{ sc.course.name }}</td>
  66. <td class="course-credit">{{ sc.course.credit }}</td>
  67. <td class="course-year-semester">{{ sc.course.year }} {{ sc.course.get_semester_display }}</td>
  68. <td class="course-teacher">{{ sc.course.teacher.name }}</td>
  69. <td class="course-scores">{{ sc.scores }}</td>
  70. <td class="course-comments">{{ sc.comments }}</td>
  71. {% if sc.rating == None %}
  72. <td class="course-rating">-</td>
  73. <td class="course-assessment">-</td>
  74. <td class="course-operation student-course">
  75. <input class="button" type="button" value="查看详情" onclick='location.href="{% url 'sview_detail' sc.id%}"' />
  76. <input class="button" type="button" value="评教"
  77. onclick='window.open("{% url 'evaluate' sc.id %}")' />
  78. </td>
  79. {% else %}
  80. <td class="course-rating">{{ sc.rating }}</td>
  81. <td class="course-assessment">{{ sc.assessment }}</td>
  82. <td class="course-operation student-course">
  83. <input class="button" type="button" value="查看详情" onclick='location.href="{% url 'sview_detail' sc.id%}"' />
  84. </td>
  85. {% endif %}
  86. </tr>
  87. {% endfor %}
  88. {% else %}
  89. {% for course in course_list %}
  90. <tr id="course-id-{{ course.id }}">
  91. <td class="course-no">{{ course.id }}</td>
  92. <td class="course-name">{{ course.name }}</td>
  93. <td class="course-credit">{{ course.credit }}</td>
  94. <td class="course-number">{{ course.get_current_count }}/{{ course.max_number }}</td>
  95. <td class="course-year">{{ course.year }}</td>
  96. <td class="course-semester">{{ course.get_semester_display }}</td>
  97. <td class="course-teacher">{{ course.teacher.name }}</td>
  98. <td class="course-schedule">
  99. {% for schedule in course.get_schedules %}
  100. <div>{{ schedule }}</div>
  101. {% endfor %}
  102. </td>
  103. <td class="course-operation student-course">
  104. {% if view_kind == "select"%}
  105. <input class="button" type="button" value="选课"
  106. onclick='window.open("{% url 'operate_course' course.id 'select' %}")' />
  107. {% endif %}
  108. {% if view_kind == "withdraw"%}
  109. <input class="button" type="button" value="撤课"
  110. onclick='window.open("{% url 'operate_course' course.id 'withdraw' %}")' />
  111. {% endif %}
  112. {% if view_kind == "current"%}
  113. -
  114. {% endif %}
  115. </td>
  116. </tr>
  117. {% endfor %}
  118. {% endif %}
  119. </tbody>
  120. </table>
  121. </div>
  122. {% endblock %}

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

  1. def view_course(request, view_kind):
  2. """
  3. :param view_kind:
  4. current: 查看当前课程
  5. is_end: 查看结课课程
  6. select: 选课
  7. withdraw: 撤课
  8. """
  9. user = get_user(request, "student")
  10. if not user:
  11. return redirect(reverse("login", kwargs={"kind": "student"}))
  12. is_search = False
  13. search_key = ""
  14. if request.method == "POST":
  15. search_key = request.POST.get("search")
  16. if search_key:
  17. is_search = True
  18. info = {
  19. "name": user.name,
  20. "kind": "student",
  21. }
  22. course_list = []
  23. if view_kind in ["select", "current", "withdraw", "is_end"]:
  24. if view_kind == "select":
  25. q = Q(status=2)
  26. if is_search:
  27. q = q & (Q(name__icontains=search_key) | Q(teacher__name__icontains=search_key))
  28. course_list = Course.objects.filter(q)
  29. my_course = StudentCourse.objects.filter(Q(student=user) & Q(with_draw=False))
  30. my_cids = [c.course.id for c in my_course]
  31. course_list = [c for c in course_list if c.id not in my_cids]
  32. else:
  33. q = Q(student=user) & Q(with_draw=False)
  34. if is_search:
  35. q = q & (Q(name__icontains=search_key) | Q(teacher__name__icontains=search_key))
  36. my_course = StudentCourse.objects.filter(q)
  37. if view_kind == "current":
  38. course_list = [c.course for c in my_course if c.course.status < 4]
  39. elif view_kind == "withdraw":
  40. course_list = [c.course for c in my_course if c.course.status == 2]
  41. elif view_kind == "is_end":
  42. course_list = [c for c in my_course if c.course.status >= 4]
  43. else:
  44. return HttpResponse(INVALID_REQUEST_METHOD)
  45. context = {
  46. 'info': info,
  47. 'view_kind': view_kind,
  48. 'course_list': course_list
  49. }
  50. if is_search:
  51. context["search_key"] = search_key
  52. return render(request, 'course/student/home.html', context)

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

  1. def student_home(request):
  2. 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,然后添加代码如下

  1. # 在开头导入timezone
  2. from django.utils import timezone
  3. def operate_course(request, operate_kind, course_id):
  4. """
  5. :param operate_kind:
  6. select: 选课
  7. withdraw: 撤课
  8. """
  9. user = get_user(request, "student")
  10. if not user:
  11. return redirect(reverse("login", kwargs={"kind": "student"}))
  12. if operate_kind not in ["select", "withdraw"]:
  13. return HttpResponse(ILLEGAL_KIND)
  14. elif operate_kind == "select":
  15. course = Course.objects.filter(pk=course_id).get()
  16. new_course = StudentCourse(student=user, course=course)
  17. new_course.save()
  18. elif operate_kind == "withdraw":
  19. q = Q(course__id=course_id) & Q(student=user) & Q(with_draw=False)
  20. course = StudentCourse.objects.filter(q).get()
  21. course.with_draw = True
  22. course.with_draw_time = timezone.now()
  23. course.save()
  24. return redirect(reverse("view_course", kwargs={"view_kind": operate_kind}))

3 - 结课后评教

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

先在course/forms.py中添加

  1. class RateForm(forms.ModelForm):
  2. class Meta:
  3. model = StudentCourse
  4. fields = ["course", "scores", "comments", "rating", "assessment"]
  5. course = forms.CharField(label="课程", disabled=True)
  6. scores = forms.IntegerField(label="成绩", disabled=True)
  7. comments = forms.CharField(label="老师评价", disabled=True)
  8. def __init__(self, *args, **kwargs):
  9. super().__init__(*args, **kwargs)
  10. self.initial['course'] = self.instance.course
  11. self.initial['scores'] = self.instance.scores
  12. self.initial['comments'] = self.instance.comments
  13. def clean_course(self):
  14. return self.initial['course']
  15. def clean_scores(self):
  16. return self.initial['scores']
  17. def clean_comments(self):
  18. return self.initial['comments']

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

  1. {% extends "course/nav.html" %}
  2. {% block title %}评教{% endblock %}
  3. {% block content %}
  4. <h3>评教</h3>
  5. <div class="form create-update-from">
  6. <form method="post">
  7. {% csrf_token %}
  8. {{form.as_p}}
  9. <div class="submit-button">
  10. <input type="submit" value="确定"/>
  11. <input type="button" value="返回" onclick='location.href="{{ return_url }}"' />
  12. </div>
  13. </form>
  14. </div>
  15. {% endblock %}

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

  1. class RateUpdateView(UpdateView):
  2. model = StudentCourse
  3. form_class = RateForm
  4. template_name = 'course/student/rating.html'
  5. def get(self, request, *args, **kwargs):
  6. self.object = self.get_object()
  7. info = {}
  8. return_url = reverse("view_course", kwargs={"view_kind": "is_end"})
  9. if self.object:
  10. student = self.object.student
  11. info = {
  12. "name": student.name,
  13. "kind": "student",
  14. }
  15. return self.render_to_response(self.get_context_data(info=info, return_url=return_url))
  16. def get_success_url(self):
  17. return reverse("view_course", kwargs={"view_kind": "is_end"})

4 - 学生课程详情页

这个使用CBVs实现起来最快

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

  1. {% extends "course/nav.html" %}
  2. {% block title %}课程详情{% endblock %}
  3. {% block content %}
  4. <h3>课程详情</h3>
  5. <ul class="course-details">
  6. <li class="course-detail"><span class="detail-name">课程编号</span> {{ object.course.id }}</li>
  7. <li class="course-detail"><span class="detail-name">课程名</span> {{ object.course.name }}</li>
  8. <li class="course-detail"><span class="detail-name">学分</span> {{ object.course.credit }}</li>
  9. <li class="course-detail"><span class="detail-name">课程人数/最大人数</span> {{ object.course.get_current_count }}/{{ object.course.max_number }}</li>
  10. <li class="course-detail"><span class="detail-name">年份</span> {{ object.course.year }}</li>
  11. <li class="course-detail"><span class="detail-name">学期</span> {{ object.course.get_semester_display }}</li>
  12. <li class="course-detail"><span class="detail-name">教师</span> {{ object.course.teacher.name }}</li>
  13. <li class="course-detail"><span class="detail-name">上课时间</span>
  14. <span class="course-schedules">
  15. {% for schedule in object.course.get_schedules %}
  16. <div class="course-schedule">{{ schedule }}</div>
  17. <div class="course-schedule">{{ schedule }}</div>
  18. {% endfor %}
  19. </span>
  20. </li>
  21. <li class="course-detail"><span class="detail-name">得分</span>
  22. {% if object.scores != None %}{{ object.scores }}{% else %} - {% endif %}
  23. </li>
  24. <li class="course-detail"><span class="detail-name">评语</span>
  25. {% if object.comments != None %}{{ object.comments }}{% else %} - {% endif %}
  26. </li>
  27. <li class="course-detail"><span class="detail-name">学生评分</span>
  28. {% if object.rating != None %}{{ object.rating }}{% else %} - {% endif %}
  29. </li>
  30. <li class="course-detail"><span class="detail-name">学生评价</span>
  31. {% if object.assessment != None %}{{ object.assessment }}{% else %} - {% endif %}
  32. </li>
  33. </ul>
  34. <input type="button" value="返回" onclick='location.href="{% url 'view_course' 'is_end'%}"' />
  35. {% endblock %}

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

  1. class StudentCourseDetailView(DetailView):
  2. model = StudentCourse
  3. template_name = 'course/student/course.html'
  4. def get(self, request, *args, **kwargs):
  5. self.object = self.get_object()
  6. context = self.get_context_data(object=self.object)
  7. if self.object:
  8. context["info"] = {
  9. "name": self.object.student.name,
  10. "kind": "student",
  11. }
  12. return self.render_to_response(context)

5 - 添加路由

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

修改后的course/urls.py如下

  1. from django.urls import path
  2. from course.views import *
  3. from course.cbvs import ScoreUpdateView, RateUpdateView, StudentCourseDetailView
  4. urlpatterns = [
  5. path('<slug:kind>/', home, name="course"),
  6. path('teacher/create_course', create_course, name="create_course"),
  7. path('teacher/view_detail/<int:course_id>', view_detail, name="view_detail"),
  8. path('teacher/create_schedule/<int:course_id>', create_schedule, name="create_schedule"),
  9. path('teacher/delete_schedule/<int:schedule_id>', delete_schedule, name="delete_schedule"),
  10. path('teacher/score/<int:pk>', ScoreUpdateView.as_view(), name="score"),
  11. path('teacher/handle_course/<int:course_id>/<int:handle_kind>', handle_course, name="handle_course"),
  12. path('student/view/<slug:view_kind>', view_course, name="view_course"),
  13. path('student/operate/<int:course_id>/<slug:operate_kind>', operate_course, name="operate_course"),
  14. path('student/evaluate/<int:pk>', RateUpdateView.as_view(), name="evaluate"),
  15. path('student/view_detail/<int:pk>', StudentCourseDetailView.as_view(), name="sview_detail"),
  16. ]

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. JSP页面属性

    一.JSP指令 <%@指令名属性名=属性值 %> page指令: 定义页面是如何解析 include指令: 静态包含 taglib指令: 在页面引入标签呢库. 1.page指令属性 imp ...

  2. C++ 可变数组实现

    话不多说,直接上代码,看注释 template<class T> // 支持传入泛型,但string这种可变长度的类型还不支持 class Array { int mSize = 0, m ...

  3. CSS3思维导图

  4. mysql8.0.20安装配置教程

    mysql配置安装教程 1.下载mysql8.0.20安装包 下载地址: https://dev.mysql.com/downloads/mysql/.找到安装包后下载.(官网为英文,如果看不懂的小伙 ...

  5. 01Prism WPF 入门实战 - 项目准备

    1.概要 这一系列将进行Prism+WPF技术的实战讲解.实战项目内容选型为Email邮件收发的客户端(WeMail),项目结构简单方便大家理解. 相关技术:C#.WPF.Prism 软件开发环境:V ...

  6. windos10环境下编译python3版pjsua库

    环境:windows10_x64python3.9_x64pjsua-2.10vs2015 pjsua编译参考这里: https://www.cnblogs.com/MikeZhang/p/pjsip ...

  7. 《手把手教你》系列技巧篇(三十一)-java+ selenium自动化测试- Actions的相关操作-番外篇(详解教程)

    1.简介 上一篇中,宏哥说的宏哥在最后提到网站的反爬虫机制,那么宏哥在自己本地做一个网页,没有那个反爬虫的机制,谷歌浏览器是不是就可以验证成功了,宏哥就想验证一下自己想法,于是写了这一篇文章,另外也是 ...

  8. 互联网公司作息表「GitHub 热点速览 v.21.42」

    作者:HelloGitHub-小鱼干 检测一家公司是否值得一去,除了高薪之外,还有时薪的算法.即便是同样的时薪,在一家能随时摸鱼的公司,岂不是人生快事.WorkingTime 便是上周很火的互联网作息 ...

  9. 痞子衡嵌入式:超级下载算法RT-UFL v1.0在恩智浦MCUXpresso IDE下的使用

    痞子衡主导的"学术"项目 <RT-UFL - 一个适用全平台i.MXRT的超级下载算法设计> v1.0 版发布近 4 个月了,部分客户已经在实际项目开发调试中用上了这个 ...

  10. 八大排序算法之基数排序(python实现)

    [写在前面] 参考文章: https://blog.csdn.net/nrsc272420199/article/details/82691596[给出的示例图,简单易懂,但是对于没一轮循环没有讲解的 ...