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 效果

創建課程頁面:

教師主頁:

教師課程詳情頁:

添加課程時刻表頁面:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM