積分管理

為了鼓勵學生繳交作業,在這個專案裡設計了一個積分的機制,讓學生以繳交作業來累積點數,在課程的修課名單中也會增加一個欄位顯示每位學生目前所獲取的點數,以期透過同儕間的競爭心理,激勵學生繳交作業。

學生每次繳交作業可以取得 2 個積點,當教師完成評分時,受評的學生的作業成績如果超過 90 分可以獲得額外的 2 個積點,超過 80 分可以獲得額外 1 個積點。

定義積分紀錄資料模型

直接將積分紀錄的資料模型定義在現存的應用程式內即可,這邊選擇將其定義在應用程式 user 之下。請開啟 user/models.py,修改第 3 行並新增第 35 - 47 行

from course.models import Course, Assignment
class PointHistory(Model): # 使用者積點紀錄 user = ForeignKey(User, CASCADE, related_name='point_list') assignment = ForeignKey(Assignment, CASCADE, related_name='+') reason = CharField('積點原因', max_length=100) point = IntegerField('點數', default=0) created = DateTimeField('積點時間', auto_now_add=True) def __str__(self): return "{}: {} {}點".format( self.created, self.reason, self.point )

定義路徑規則

取得積點的動作會伴隨著學生上傳作品或教師批閱作品時發生,而顯示使用者積點則預計在顯示修課名單時一併顯示每位學生目前所獲得的積點數量,所以不需另外定義其他路徑規則。

修改相關視圖類別

請開啟應用程式 course 的視圖定義檔 course/views.py,依下述方式修改:

from user.models import Message, PointHistory

修課名單新增使用者積點統計

class CourseUsers(CourseAccessMixin, ListView): # 修課名單 permission = COURSE_PERM_MEMBER extra_context = {'title': '修課名單'} template_name = 'course/user_list.html' def get_queryset(self): return self.course.enroll_set.select_related('stu')\ .annotate( points = Sum('stu__point_list__point') ).order_by('seat')

學生繳交作業(上傳作品)取得 2 個積點

修改 WorkSubmit 視圖類別,新增點數紀錄:

class WorkSubmit(CourseAccessMixin, CreateView): extra_context = {'title': '繳交作業'} permission = COURSE_PERM_STUDENT model = Work fields = ['memo', 'attachment'] template_name = 'form.html' def form_valid(self, form): form.instance.assignment = Assignment(id=self.kwargs['aid']) form.instance.user = self.request.user # 繳交作業累積 2 點積分 PointHistory( user = form.instance.user, assignment = form.instance.assignment, reason = '繳交作業', point = 2 ).save() return super().form_valid(form) def get_success_url(self): return reverse( 'assignment_view', args=[self.course.id, self.object.assignment.id] )

教師評分

修改 WorkScore 視圖類別,新增點數紀錄:

class WorkScore(CourseAccessMixin, UpdateView): extra_context = {'title': '批改作業'} permission = COURSE_PERM_TEACHER model = Work fields = ['score'] pk_url_kwarg = 'wid' def get_success_url(self): return reverse( 'assignment_view', args=[self.course.id, self.object.assignment.id] ) def get_form(self): form = super().get_form() form.fields['score'] = forms.ChoiceField( label = '成績', choices = [ (100, "你好棒(100分)"), (90, "90分"), (80, "80分"), (70, "70分"), (60, "60分"), ], ) self.oldscore = self.object.score # 本次評分前原始成績 return form def form_valid(self, form): def score_to_point(score): # 成績轉換為點數 return 2 if score >= 90 else 1 if score >= 80 else 0 oscore = self.oldscore # 原始成績 nscore = form.instance.score # 本次成績 opoint = score_to_point(oscore) # 原始成績積點 npoint = score_to_point(nscore) # 本次成績積點 if opoint != npoint: PointHistory( user = self.object.user, assignment = self.object.assignment, reason = f'教師評分: {oscore} -> {nscore}', point = npoint - opoint, ).save() return super().form_valid(form)

修改頁面範本

修課學生列表

開啟 templates/course/user_list.html,新增第 12, 24 行

<thead> <tr> <th>學校</th> <th>帳號</th> <th>座號</th> <th>姓名</th> <th>積分</th> <th>最近登入時間</th>
{% for enroll in enroll_list %} <tr> <td>{{ enroll.stu.last_name }}</td> <td>{{ enroll.stu.username }}</td> <td>{{ enroll.seat }}</td> <td>{{ enroll.stu.first_name }}</td> <td>{{ enroll.points|default:0 }}</td> <td>{{ enroll.stu.last_login|date:"Y-m-d H:i" }}</td>

使用者個人積分紀錄列表

修改檢視使用者頁面範本,插入第 18 - 32 行列出使用者積點紀錄清單:

{% endif %} <div class="card-title">個人積點</div> <ul> {% for ph in tuser.point_list.all reversed %} <li> {{ ph.created|date:"Y-m-d H:i"}} {{ ph.reason }}: {% with aid=ph.assignment.id cid=ph.assignment.course.id %} <a href="{% url 'assignment_view' cid aid %}"> {{ ph.assignment.title }} </a> {% endwith %} <span class="badge badge-warning">{{ ph.point }}</span> </li> {% endfor %} </ul> <div class="card-title">選修的課程</div>