zoukankan      html  css  js  c++  java
  • Django 小实例S1 简易学生选课管理系统 10 老师课程业务实现

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

    课程模块中,老师将要使用到的功能有:

    • 创建课程
    • 添加、删除课程时刻表
    • 查看课程列表
    • 操作课程:修改状态,给学生打分

    这里一个一个实现

    首先,在course/views.py中将课程的模型类全部导入,以便后面使用

    from .models import Course, Schedule, StudentCourse
    

    1 - 创建课程

    首先需要实现的是创建课程的表单,
    新建course/forms.py如下

    from django import forms
    from .models import Course, Schedule, StudentCourse
    
    
    class CourseForm(forms.ModelForm):
    
        class Meta:
            model = Course
            exclude = ['status', 'teacher']
    

    同时对于新建课程的请求,在constants.py中添加一个非法请求的响应如下

    INVALID_REQUEST_METHOD = "Invalid request method."
    

    新建对应模板templates/course/teacher/create_course.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='window.open("{% url 'course' "teacher"%}")' />
                </div>
            </form>
        </div>
    {% endblock %}
    

    再在course/views.py中导入CourseForm类和INVALID_REQUEST_METHOD常量,然后添加代码如下

    def create_course(request):
        user = get_user(request, "teacher")
        if not user:
            return redirect(reverse("login", kwargs={"kind": "teacher"}))
    
        info = {
            "name": user.name,
            "kind": "teacher",
        }
    
        if request.method == 'POST':
            form = CourseForm(request.POST)
            if form.is_valid():
                obj = form.save(commit=False)
                obj.status = 1
                obj.teacher = user
    
                obj.save()
                return redirect(reverse("course", kwargs={"kind": "teacher"}))
        elif request.method == 'GET':
            form = CourseForm()
        else:
            return HttpResponse(INVALID_REQUEST_METHOD)
    
        return render(request, 'course/teacher/create_course.html', {'info': info, 'form': form})
    

    2 - 添加、删除课程时刻表

    先需要实现的是添加课程时刻表的表单,

    course/forms.py中添加代码如下

    class ScheduleForm(forms.ModelForm):
        class Meta:
            model = Schedule
            exclude = ["course"]
    

    新建对应模板templates/course/teacher/create_schedule.html如下

    {% extends "course/nav.html" %}
    {% block title %}创建时刻表{% endblock %}
    {% block content %}
        <h3>创建时刻表:&nbsp;&nbsp;&nbsp;&nbsp;[{{ course.id }}] {{ course.name }}</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='window.open("{% url 'view_detail' course.id%}")' />
                </div>
            </form>
        </div>
    {% endblock %}
    

    course/views.py中导入这个表单,
    然后添加代码如下

    def create_schedule(request, course_id):
        user = get_user(request, "teacher")
        if not user:
            return redirect(reverse("login", kwargs={"kind": "teacher"}))
    
        info = {
            "name": user.name,
            "kind": "teacher",
        }
    
        course = Course.objects.get(pk=course_id)
    
        if request.method == 'POST':
            form = ScheduleForm(request.POST)
            if form.is_valid():
                obj = form.save(commit=False)
                obj.course = course
                obj.save()
    
                return redirect(reverse("view_detail", kwargs={"course_id": course_id}))
        elif request.method == 'GET':
            form = ScheduleForm()
        else:
            return HttpResponse(INVALID_REQUEST_METHOD)
    
        return render(request, 'course/teacher/create_schedule.html', {'info': info, 'form': form, "course": course})
    
    
    def delete_schedule(request, schedule_id):
        user = get_user(request, "teacher")
        if not user:
            return redirect(reverse("login", kwargs={"kind": "teacher"}))
    
        schedule = Schedule.objects.get(pk=schedule_id)
    
        course_id = request.GET.get("course_id") or schedule.course.id
    
        schedule.delete()
    
        return redirect(reverse("view_detail", kwargs={"course_id": course_id}))
    

    3 查看课程列表

    在本项目中,老师和学生的个人主页就是其课程主页,将展示其所有课程列表。
    为老师的课程主页添加模板templates/course/teacher/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>
    
                <input class="button right-button" type="button" value="创建课程"  onclick='window.open("{% url 'create_course' %}")' />
            </div>
            <table class="item-list course-list">
                <thead>
                    <tr>
                        <th class="course-no">课程编号</th>
                        <th class="course-name">名称</th>
                        <th class="course-credit">学分</th>
                        <th class="course-number">当前人数<br>/总人数</th>
                        <th class="course-year">年份</th>
                        <th class="course-semester">学期</th>
                        <th class="course-status">状态</th>
                        <th class="course-operation">操作</th>
                    </tr>
                </thead>
                <tbody>
                    {% 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-status">{{ course.get_status_text }}</td>
                        <td class="course-operation">
                            {% if course.status < 4 %}
                                <input class="button right-button" type="button" value="{{ course.get_op_text }}"
                                  onclick='location.href="{% url 'handle_course' course.id course.status %}"' />
                            {% endif %}
                            {% if course.status == 4 %}
                            {# 结课后给分 #}
                                <input class="button right-button" type="button" value="{{ course.get_op_text }}"
                                       onclick='location.href="{% url 'view_detail' course.id %}"' />
                            {% else %}
                                <input class="button right-button" type="button" value="查看详情"
                                       onclick='location.href="{% url 'view_detail' course.id %}"' />
                            {% endif %}
                        </td>
                        </tr>
                    {% endfor %}
                </tbody>
    
            </table>
        </div>
    {% endblock %}
    

    查看课程列表要写在老师的主页视图中
    即修改course/views.py中的teacher_home如下

    def teacher_home(request):
        user = get_user(request, "teacher")
        if not user:
            return redirect(reverse("login", kwargs={"kind": "teacher"}))
    
        info = {
            "name": user.name,
            "kind": "teacher",
        }
    
        is_search = False
        search_key = ""
        if request.method == "POST":
            search_key = request.POST.get("search")
            if search_key:
                is_search = True
    
        context = {"info": info}
        q = Q(teacher=user)
        if is_search:
            q = q & Q(name__icontains=search_key)
            context["search_key"] = search_key
    
        context["course_list"] = Course.objects.filter(q).order_by('status')
    
        return render(request, 'course/teacher/home.html', context)
    

    里面使用了django.db.models.Q类,所以要在开头添加代码from django.db.models import Q导入这个类

    补充说明:这里面还实现了一个搜索框,能够根据关键词去搜索课程。
    为了不使用js,搜索框的信息是通过post表单信息来提交的。

    4 操作课程

    老师在课程主页,可以进行常规的课程状态修改:
    开始选课,结束选课,结课。
    而打分则需要在课程详情页去给。
    所以这里一方面要实现一个课程主页的操作视图,
    也要实现一个课程详情页视图,打分在本文第五部分去做。

    先添加一个课程详情页的模板文件templates/course/teacher/course.html如下:

    {% extends "course/nav.html" %}
    {% block title %}课程详情{% endblock %}
    {% block content %}
        <h3>课程详情<input class="button right-button" type="button" value="返回主页"
                       onclick='window.open("{% url 'course' 'teacher'%}")'/></h3>
        <table class="item-list detail-list">
            <thead>
                <tr>
                    <th>课程编号</th>
                    <th>名称</th>
                    <th>学分</th>
                    <th>当前人数/总人数</th>
                    <th>年份</th>
                    <th>学期</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>{{ course.id }}</td>
                    <td>{{ course.name }}</td>
                    <td>{{ course.credit }}</td>
                    <td>{{ course.get_current_count }}/{{ course.max_number }}</td>
                    <td>{{ course.year }}</td>
                    <td>{{ course.get_semester_display }}</td>
                </tr>
            </tbody>
        </table>
    
        <h3>上课时间<input class="button right-button" type="button" value="添加时间表" onclick='window.open("{% url 'create_schedule' course.id%}")'/></h3>
        <table class="item-list schedule-list">
            <thead>
                <tr>
                    <th class="schedule-no">编号</th>
                    <th class="schedule-no">详情</th>
                    <th class="schedule-no">操作</th>
                </tr>
            </thead>
            <tbody>
                {% for schedule in schedules %}
                <tr>
                    <td>{{ schedule.id }}</td>
                    <td>{{ schedule }}</td>
                    <td>
                        <input class="button" type="button" value="删除"
                               onclick='window.open("{% url 'delete_schedule' schedule.id%}?course_id={{ course.id }}")'/>
                    </td>
                </tr>
                {% endfor %}
            </tbody>
        </table>
    
        <h3>学生列表
            {% if course.status == 4 %}
                <input class="button right-button" type="button" value="给分完成" onclick='location.href="{% url 'handle_course' course.id 4%}"' />
            {% endif %}
        </h3>
        <table class="item-list student-list">
            <thead>
                <tr>
                    <th class="student-no">学生学号</th>
                    <th class="student-name">学生姓名</th>
                    <th class="student-email">学生邮箱</th>
                    <th class="student-score">得分</th>
                    <th class="student-comments">评价</th>
                    <th class="operation">操作</th>
                </tr>
            </thead>
            <tbody>
                {% for cs in course_students %}
                <tr>
                    <td>{{ cs.student.get_id}}</td>
                    <td>{{ cs.student.name }}</td>
                    <td>{{ cs.student.email }}</td>
                    <td>
                        {% if cs.scores == None %}-{% endif %}
                        {% if cs.scores != None %}{{ cs.scores }}{% endif %}
                    </td>
                    <td>
                        {% if cs.scores == None %}-{% endif %}
                        {% if cs.scores != None %}{{ cs.comments }}{% endif %}
                    </td>
                    <td class="operation">
                        {% if course.status == 4 %}
                            {% if cs.scores == None %}
                                <input class="button right-button" type="button" value="给分"
                                   onclick='location.href="{% url 'score' cs.id%}"' />
                            {% else %}
                                <input class="button right-button" type="button" value="修改成绩"
                                   onclick='location.href="{% url 'score' cs.id%}?update=1"' />
                            {% endif %}
                        {% else %}
                            -
                        {% endif %}
                    </td>
                </tr>
                {% endfor %}
            </tbody>
        </table>
    
        {% if course.status == 5 %}
        <h3>学生评价</h3>
        <table class="item-list student-list">
            <thead>
                <tr>
                    <th class="student-score">学生评分</th>
                    <th class="student-comments">学生评价</th>
                </tr>
            </thead>
            <tbody>
                {% for cs in sorted_course_students %}
                {% if cs.rating != None %}
                <tr>
                    <td>{{ cs.rating }}</td>
                    <td>{{ cs.assessment }}</td>
                </tr>
                {% endif %}
                {% endfor %}
            </tbody>
        </table>
        {% endif %}
    {% endblock %}
    

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

    def handle_course(request, course_id, handle_kind):
        """
        :param request:
        :param course_id:
        :param handle_kind:
                1: "开始选课",
                2: "结束选课",
                3: "结课",
                4: "给分完成"
        :return:
        """
        user = get_user(request, "teacher")
        if not user:
            return redirect(reverse("login", kwargs={"kind": "teacher"}))
    
        info = {
            "name": user.name,
            "kind": "teacher",
        }
    
        course = Course.objects.get(pk=course_id)
        if course.status == handle_kind and course.status < 5:
            if course.status == 4:
                scs = StudentCourse.objects.filter(course=course)
                all_given = True
                res = ""
                for sc in scs:
                    if sc.scores is None:
                        all_given = False
                        res += "<div>%s 未打分</div>" % sc.student
    
                if all_given:
                    course.status += 1
                    course.save()
                    return redirect(reverse("view_detail", kwargs={"course_id": course.id}))
                else:
                    return HttpResponse(res)
            else:
                course.status += 1
                course.save()
    
        course_list = Course.objects.filter(teacher=user)
        return render(request, 'course/teacher/home.html', {'info': info, 'course_list': course_list})
    
    
    def view_detail(request, course_id):
        user = get_user(request, "teacher")
        if not user:
            return redirect(reverse("login", kwargs={"kind": "teacher"}))
    
        info = {
            "name": user.name,
            "kind": "teacher",
        }
    
        course = Course.objects.get(pk=course_id)
        c_stu_list = StudentCourse.objects.filter(course=course)
        sche_list = Schedule.objects.filter(course=course)
    
        context = {
            "info": info,
            "course": course,
            "course_students": c_stu_list,
            "schedules": sche_list
        }
    
        if course.status == 5:
            sorted_cs_list = sorted(c_stu_list, key=lambda cs: cs.scores)
            context["sorted_course_students"] = sorted_cs_list
    
        return render(request, "course/teacher/course.html", context)
    

    5 打分

    学生的分数是记录在学生课程关系表中的,
    在学生选课成功后会新建一条对应的数据。
    给分,则是修改其中的分数字段,即对学生课程表模型进行更新。

    这里我们首选CBVs中的UpdateView,
    不过要先给这个视图建立一个表单,在course/forms.py中添加代码如下

    class ScoreForm(forms.ModelForm):
        class Meta:
            model = StudentCourse
            fields = ["student", "course", "scores", "comments"]
    
        student = forms.CharField(label="学生", disabled=True)
        # course = forms.CharField(widget=forms.TextInput(attrs={'readonly': 'readonly'}))
        course = forms.CharField(label="课程", disabled=True)
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.initial['student'] = self.instance.student
            self.initial['course'] = self.instance.course
    
        def clean_student(self):
            return self.initial['student']
    
        def clean_course(self):
            return self.initial['course']
    

    新建course/cbvs.py如下:

    from django.views.generic.edit import DeleteView, CreateView, UpdateView
    from django.views.generic.detail import DetailView
    from django.shortcuts import render, reverse, redirect
    
    # Relative import of GeeksModel
    from .models import Schedule, StudentCourse
    from .forms import ScoreForm
    
    
    class ScoreUpdateView(UpdateView):
        model = StudentCourse
        form_class = ScoreForm
        template_name = 'course/teacher/score.html'
    
        def get(self, request, *args, **kwargs):
            self.object = self.get_object()
    
            title = "给分"
            if request.GET.get("update"):
                title = "修改成绩"
    
            info = {}
            return_url = reverse("course", kwargs={"kind": "teacher"})
            if self.object:
                teacher = self.object.course.teacher
                info = {
                    "name": teacher.name,
                    "kind": "teacher",
                }
                return_url = reverse("view_detail", kwargs={"course_id": self.object.course.id})
    
            return self.render_to_response(self.get_context_data(info=info, title=title, return_url=return_url))
    
        def get_success_url(self):
            if self.object:
                return reverse("view_detail", kwargs={"course_id": self.object.course.id})
            else:
                return reverse("course", kwargs={"kind": "teacher"})
    

    同时补上其对应的模板文件templates/course/teacher/score.html如下

    {% extends "course/nav.html" %}
    {% block title %}{{ title }}{% endblock %}
    {% block content %}
        <h3>{{ title }}</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 %}
    

    5 添加url

    上面已经把老师需要的视图方法全部实现完毕了,接下来就是添加到路由里面。
    修改后的course/urls.py如下

    from django.urls import path
    from course.views import *
    from course.cbvs import ScoreUpdateView
    
    
    urlpatterns = [
        path('<slug:kind>/', home, name="course"),
        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"),
    ]
    

    6 效果

    创建课程页面:

    教师主页:

    教师课程详情页:

    添加课程时刻表页面:

  • 相关阅读:
    FreeCommander 学习手册
    String详解, String和CharSequence区别, StringBuilder和StringBuffer的区别 (String系列之1)
    StringBuffer 详解 (String系列之3)
    StringBuilder 详解 (String系列之2)
    java io系列26之 RandomAccessFile
    java io系列25之 PrintWriter (字符打印输出流)
    java io系列24之 BufferedWriter(字符缓冲输出流)
    java io系列23之 BufferedReader(字符缓冲输入流)
    java io系列22之 FileReader和FileWriter
    java io系列21之 InputStreamReader和OutputStreamWriter
  • 原文地址:https://www.cnblogs.com/BigShuang/p/14324500.html
Copyright © 2011-2022 走看看