1.初始化 course_record, study_record.
2.學習記錄
3.錄入成績
4.顯示成績 ajax 查詢 柱狀圖展現成績 highcharts
5.上傳做業(os模塊)
6.下載做業javascript
class StudyConfig(ModelStark): def display_record(self, obj=None, header=False): if header: return "簽到" return obj.get_record_display() # 存的值對應的中文 def display_score(self, obj=None, header=False): if header: return "成績" return obj.get_score_display() # 存的值對應的中文 list_display = ["student", "course_record", display_record, display_score] site.register(StudyRecord, StudentConfig)
不取字段值而是拼上get和display取存的值對應的中文。css
在models中choices對應的是一個元組。html
class ShowList(object): """展現頁面類""" def get_body(self): """構建表單數據""" """代碼省略""" # 針對choices屬性 if field_obj.choices: val = getattr(obj, "get_" + field + "_display") else: val = getattr(obj, field) # 拿到的關聯對象 處理不了多對多 ##################自定義配置############# class StudyConfig(ModelStark): list_display = ["student", "course_record", "record", "score"] site.register(StudyRecord, StudentConfig)
錄入學習記錄:java
class CourseRecordConfig(ModelStark): list_display = ["class_obj", "day_num", "teacher"] def patch_studyRecord(self, request, queryset): print("=====>",queryset) """ 提交批量操做獲取的queryset <QuerySet [<CourseRecord: python基礎(9期) day94>, <CourseRecord: python基礎(9期) day95>]> """ temp = [] for course_record in queryset: # 過濾出班級全部的學生 學生表classlist關聯班級表 student_list = Student.objects.filter(class_list__id=course_record.class_obj.pk) # 學生的班級id和課程記錄班級的id進行比對 拿到班級全部的學生 for student in student_list: # 拿到學生對象 obj = StudyRecord(student=student, course_record=course_record) temp.append(obj) StudyRecord.objects.bulk_create(temp) # 批量插入 actions = [patch_studyRecord, ] patch_studyRecord.short_description = "批量生產學習記錄" """ def get_action_list(self): # 獲取自定義批量操做 temp = [] for action in self.actions: temp.append({ "name": action.__name__, # 函數.__name__:拿到函數名 "desc": action.short_description }) # [{"name": "patch_init", "desc": "批量處理"}] return temp """ site.register(CourseRecord, CourseRecordConfig)
注意python
(1)批量插入操做:jquery
StudyRecord.objects.bulk_create(temp)
(2)跨表查詢班級全部的學生ajax
# 過濾出班級全部的學生 學生表classlist關聯班級表 student_list = Student.objects.filter(class_list__id=course_record.class_obj.pk) # 學生的班級id和課程記錄班級的id進行比對 拿到班級全部的學生
過濾course_record關聯的班級對應的全部的學生。django
(3)批量操做別名描述short_descriptionbootstrap
這是因爲在Modelstark中源碼get_action_list有關於action別名的配置:數組
def get_action_list(self): # 獲取自定義批量操做 temp = [] for action in self.actions: temp.append({ "name": action.__name__, # 函數.__name__:拿到函數名 "desc": action.short_description }) # [{"name": "patch_init", "desc": "批量處理"}] return temp
學習記錄生產成功:
根據課程記錄來過濾學習記錄,這個須要修改service/stark.py中的get_filter_condition。由於這個其實也是一種filter過濾,但並無寫在filter_list中。
class ModelStark(object): def get_filter_condition(self, request): """拿到過濾條件""" filter_condition = Q() # 默認查詢條件爲且 and for filter_field, val in request.GET.items(): # 過濾字段、查詢的值 去除fitler_field拼接的__id # if filter_field in self.list_filter: # 僅限過濾使用,只處理filter過濾列表的鍵值 if filter_field != "page": # (分頁等排除) ?page=2&course_record=1 filter_condition.children.append((filter_field, val)) # 添加的是一個元組 return filter_condition
修改後僅排除了?page=1這樣的狀況,能夠在頁面上訪問http://127.0.0.1:8000/stark/crm/studyrecord/?course_record=2拿到過濾結果:
class CourseRecordConfig(ModelStark): # 定製一欄新的表格 def record(self, obj=None, header=False): if header: return "checked" return mark_safe("<a href='/stark/crm/studyrecord/?course_record=%s'>記錄</a>" % obj.pk) # mark_safe取消轉義 list_display = ["class_obj", "day_num", "teacher", record] def patch_studyRecord(self, request, queryset): temp = [] for course_record in queryset: # 過濾course_record關聯的班級對應的全部的學生 學生表classlist關聯班級表 student_list = Student.objects.filter(class_list__id=course_record.class_obj.pk) # 學生的班級id和課程記錄班級的id進行比對 拿到班級全部的學生 for student in student_list: # 拿到學生對象 obj = StudyRecord(student=student, course_record=course_record) temp.append(obj) StudyRecord.objects.bulk_create(temp) # 批量插入 actions = [patch_studyRecord, ] patch_studyRecord.short_description = "批量生產學習記錄" site.register(CourseRecord, CourseRecordConfig)
課程記錄頁面:
點擊記錄跳轉學習記錄頁面:
給學習記錄訂製遲到批量操做
class StudyConfig(ModelStark): list_display = ["student", "course_record", "record", "score"] def patch_late(self, request, queryset): queryset.update(record="late") patch_late.short_description = "遲到" actions = [patch_late, ] site.register(StudyRecord, StudyConfig)
批量調整上課記錄爲遲到:
class CourseRecordConfig(ModelStark): def score(self, request, course_record_id): return HttpResponse("score") def extra_url(self): """擴展考勤記錄url""" temp = [] temp.append(url(r"record_score/(\d+)", self.score)) return temp # 定製一欄新的表格 def record(self, obj=None, header=False): if header: return "考勤" return mark_safe("<a href='/stark/crm/studyrecord/?course_record=%s'>記錄</a>" % obj.pk) # mark_safe取消轉義 def record_score(self, obj=None, header=False): if header: return "錄入成績" # http://127.0.0.1:8000/stark/crm/studyrecord/?course_record=1 CourseRecord主鍵值 return mark_safe("<a href='record_score/%s'>錄入成績</a>" % obj.pk) list_display = ["class_obj", "day_num", "teacher", record, record_score] def patch_studyRecord(self, request, queryset): """代碼省略"""
注意:
def record_score(self, obj=None, header=False): if header: return "錄入成績" # http://127.0.0.1:8000/stark/crm/studyrecord/?course_record=1 CourseRecord主鍵值 return mark_safe("<a href='record_score/%s'>錄入成績</a>" % obj.pk)
def score(self, request, course_record_id): return HttpResponse("score") def extra_url(self): """擴展考勤記錄url""" temp = [] temp.append(url(r"record_score/(\d+)", self.score)) return temp
點擊錄入成績,跳轉對應頁面:
class CourseRecordConfig(ModelStark): def score(self, request, course_record_id): study_record_list = StudyRecord.objects.filter(course_record=course_record_id) # 過濾出對應課程(哪一個班級哪一天)的學習記錄 score_choices = StudyRecord.score_choices return render(request, "score.html", locals())
注意:
(1)study_record_list拿到對應課程的學習記錄(哪一天哪一個班級)
(2)score_choices拿到StudyRecord的score_choices字段內容傳遞給模板
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css"> <script src="/static/js/jquery-1.12.4.min.js"></script> </head> <body> <h3>錄入成績</h3> <div class="container"> <div class="row"> <div class="col-md-9 col-md-offset-1"> <form action="" method="post"> {% csrf_token %} <table class="table table-bordered table-striped"> <thead> <tr> <th>學生姓名</th> <th>考勤</th> <th>成績</th> <th>批語</th> </tr> </thead> <tbody> {% for study_record in study_record_list %} <tr> <td>{{ study_record.student }}</td> {# <td>{{ study_record.record }}</td> 針對帶有choices的字段使用拼接get和display #} <td>{{ study_record.get_record_display }}</td> <td style="width: 150px; padding: 10px 20px;"> <select name="" id="" class="form-control"> {% for item in score_choices %} <option value="{{ item.0 }}">{{ item.1 }}</option> {% endfor %} </select> </td> <td> <textarea name="" id="" cols="30" rows="4" class="form-control"></textarea> </td> </tr> {% endfor %} </tbody> </table> <input type="submit" class="btn btn-default pull-right"> </form> </div> </div> </div> </body> </html>
注意:
針對Model中的record字段:
record = models.CharField("上課紀錄", choices=record_choices, default="checked", max_length=64)
要顯示遲到簽到信息須要拼接get和display取值
{# <td>{{ study_record.record }}</td> 針對帶有choices的字段使用拼接get和display #} <td>{{ study_record.get_record_display }}</td>
顯示效果:
<td style="width: 150px; padding: 10px 20px;"> <select name="score" id="" class="form-control"> {% for item in score_choices %} <option value="{{ item.0 }}">{{ item.1 }}</option> {% endfor %} </select> </td>
item.0拿到score_choices中每一個元組的第一個值即分數,item.1拿到元組第二個值即評分等級。顯示效果以下:
<td> <textarea name="homework_note" id="" cols="30" rows="4" class="form-control"></textarea> </td>
顯示效果以下所示:
<body> <h3>錄入成績</h3> <div class="container"> <div class="row"> <div class="col-md-9"> <form action="" method="post"> {% csrf_token %} <table class="table table-bordered table-striped"....> <input type="submit" class="btn btn-default pull-right"> </form> </div> </div> </div> </body>
顯示效果:
class CourseRecordConfig(ModelStark): def score(self, request, course_record_id): if request.method == "POST": # print(request.POST) # <QueryDict: {'csrfmiddlewaretoken': ['20Zp72PlKJzRZ6HAYkMX0veCIxynx5nogd8LsKKkdZb7mRLrAb1KtN1PDTljh7Jq'], 'score_4': ['70'], 'homework_note_4': ['學習理解能力差'], 'score_5': ['40'], 'homework_note_5': ['無紀律無組織'], 'score_6': ['90'], 'homework_note_6': ['學習能力優秀']}> for key, value in request.POST.items(): if key == "csrfmiddlewaretoken": continue # 分隔score_1爲例,score爲字段 1爲某一個學生學習記錄的pk值 field, pk = key.rsplit("_", 1) # 從右開始以"_"分隔數據,且僅分隔一次 if field == "score": StudyRecord.objects.filter(pk=pk).update(score=value) else: StudyRecord.objects.filter(pk=pk).update(homework_note=value) return redirect(request.path) # 拿到當前POST請求路徑重定向GET請求 else: study_record_list = StudyRecord.objects.filter(course_record=course_record_id) # 過濾出對應課程(哪一個班級哪一天)的學習記錄 score_choices = StudyRecord.score_choices return render(request, "score.html", locals())
同時還伴隨有score.html的變動:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css"> <script src="/static/js/jquery-1.12.4.min.js"></script> </head> <body> <h3>錄入成績</h3> <div class="container"> <div class="row"> <div class="col-md-9 col-md-offset-1"> <form action="" method="post"> {% csrf_token %} <table class="table table-bordered table-striped"> <thead> <tr> <th>學生姓名</th> <th>考勤</th> <th>成績</th> <th>批語</th> </tr> </thead> <tbody> {% for study_record in study_record_list %} <tr> <td>{{ study_record.student }}</td> {# <td>{{ study_record.record }}</td> 針對帶有choices的字段使用拼接get和display #} <td>{{ study_record.get_record_display }}</td> <td style="width: 150px; padding: 10px 20px;"> <select name="score_{{ study_record.pk }}" id="" class="form-control"> {% for item in score_choices %} {% if study_record.score == item.0 %} {# 當前成績等於item.0#} <option selected value="{{ item.0 }}">{{ item.1 }}</option> {% endif %} <option value="{{ item.0 }}">{{ item.1 }}</option> {% endfor %} </select> </td> <td> <textarea name="homework_note_{{ study_record.pk }}" id="" cols="30" rows="4" class="form-control">{{ study_record.homework_note }}</textarea> </td> </tr> {% endfor %} </tbody> </table> <input type="submit" class="btn btn-default pull-right"> </form> </div> </div> </div> </body> </html>
直接在上面的成績錄入頁面提交POST請求:
在視圖中接收POST請求,打印接收的request.POST數據:
class CourseRecordConfig(ModelStark): def score(self, request, course_record_id): if request.method == "POST": print(request.POST) """ <QueryDict: {'csrfmiddlewaretoken': ['UMfON3mW1TKIMCqWI3fqOUuRaqP9ggoL8Zoa8LhVu9mY9nuNkUudhch45MC50iKN'], 'score': ['60', '80', '90'], 'homework_note': ['朽木不可雕', '學習自覺性較差', '學習認真刻苦']}> """ return HttpResponse("123")
這是因爲全部的成績select標籤name="score",全部批語textarea標籤name="homework_note",一個鍵對應三個值,三個值組成數組。致使沒法區分誰是誰的成績和批語。
<td style="width: 150px; padding: 10px 20px;"> <select name="score_{{ study_record.pk }}" id="" class="form-control"> {% for item in score_choices %} <option value="{{ item.0 }}">{{ item.1 }}</option> {% endfor %} </select> </td> <td> <textarea name="homework_note_{{ study_record.pk }}" id="" cols="30" rows="4" class="form-control"></textarea> </td>
從新提交表單,request.POST獲取的數據以下:
class CourseRecordConfig(ModelStark): def score(self, request, course_record_id): if request.method == "POST": print(request.POST) # <QueryDict: {'csrfmiddlewaretoken': ['20Zp72PlKJzRZ6HAYkMX0veCIxynx5nogd8LsKKkdZb7mRLrAb1KtN1PDTljh7Jq'], 'score_4': ['70'], 'homework_note_4': ['學習理解能力差'], 'score_5': ['40'], 'homework_note_5': ['無紀律無組織'], 'score_6': ['90'], 'homework_note_6': ['學習能力優秀']}>
如上所示鍵帶有本身的id值,能夠更好地去錄入成績,完成處理更新操做。
Python split() 經過指定分隔符對字符串進行切片,若是參數 num 有指定值,則僅分隔 num 個子字符串。
print("yuan_alex_egon".split("_", 1)) # 只分一次 print("yuan_alex_egon".split("_", 2)) # 分兩次 print("yuan_alex_egon".rsplit("_",1)) # 從右邊開始分一次 """ ['yuan', 'alex_egon'] ['yuan', 'alex', 'egon'] ['yuan_alex', 'egon'] """
for key, value in request.POST.items(): if key == "csrfmiddlewaretoken": continue # 分隔score_1爲例,score爲字段 1爲某一個學生學習記錄的pk值 field, pk = key.rsplit("_", 1) # 從右開始以"_"分隔數據,且僅分隔一次 if field == "score": StudyRecord.objects.filter(pk=pk).update(score=value) else: StudyRecord.objects.filter(pk=pk).update(homework_note=value)
def score(self, request, course_record_id): if request.method == "POST": """代碼省略""" return redirect(request.path) # 拿到當前POST請求路徑重定向GET請求
<td style="width: 150px; padding: 10px 20px;"> <select name="score_{{ study_record.pk }}" id="" class="form-control"> {% for item in score_choices %} {% if study_record.score == item.0 %} {# 當前成績等於item.0#} <option selected value="{{ item.0 }}">{{ item.1 }}</option> {% endif %} <option value="{{ item.0 }}">{{ item.1 }}</option> {% endfor %} </select> </td> <td> <textarea name="homework_note_{{ study_record.pk }}" id="" cols="30" rows="4" class="form-control">{{ study_record.homework_note }}</textarea> </td>
這樣在POST請求提交後,get請求獲取的當前頁面,頁面保留以前錄入的數據。
class CourseRecordConfig(ModelStark): def score(self, request, course_record_id): if request.method == "POST": data = {} for key, value in request.POST.items(): # 鍵、值 if key == "csrfmiddlewaretoken": continue # 分隔score_1爲例,score爲字段 1爲某一個學生學習記錄的pk值 field, pk = key.rsplit("_", 1) # 從右開始以"_"分隔數據,且僅分隔一次 字段、主鍵 # dic = {1:{"homework_note":"", "score":90}, 2:{"homework_note": "", "score": 76}} if pk in data: # 第一次加入字典 data[pk][field] = value else: # pk已經保存在字典中 data[pk] = {field: value} print("data", data) # data {'4': {'score': '100', 'homework_note': 'dsfe '}, '5': {'score': '85', 'homework_note': 'asd a'}, '6': {'score': '50', 'homework_note': 'adad w'}} for pk, update_data in data.items(): # 主鍵、更新數據 StudyRecord.objects.filter(pk=pk).update(**update_data) return redirect(request.path) # 拿到當前POST請求路徑重定向GET請求
def score(self, request, course_record_id): if request.method == "POST": data = {} for key, value in request.POST.items(): # 鍵、值 if key == "csrfmiddlewaretoken": continue # 分隔score_1爲例,score爲字段 1爲某一個學生學習記錄的pk值 field, pk = key.rsplit("_", 1) # 從右開始以"_"分隔數據,且僅分隔一次 字段、主鍵 # dic = {1:{"homework_note":"", "score":90}, 2:{"homework_note": "", "score": 76}} if pk in data: # 第一次加入字典 data[pk][field] = value else: # pk已經保存在字典中 data[pk] = {field: value} print("data", data) # data {'4': {'score': '100', 'homework_note': 'dsfe '}, '5': {'score': '85', 'homework_note': 'asd a'}, '6': {'score': '50', 'homework_note': 'adad w'}}
for pk, update_data in data.items(): # 主鍵、更新數據 StudyRecord.objects.filter(pk=pk).update(**update_data)
update()方法對於任何結果集均有效,能夠同時更新多條記錄。
class StudentConfig(ModelStark): def score_view(self, request, sid): # sid:當前學生的id """擴展視圖""" student = Student.objects.filter(pk=sid).first() class_list = student.class_list.all() # 班級列表 return render(request, "score_view.html", locals()) def extra_url(self): """擴展路由""" temp = [] temp.append(url((r"score_view/(\d+)"), self.score_view)) return temp def score_show(self, obj=None, header=False): """查當作績""" if header: return "查當作績" return mark_safe("<a href='/stark/crm/student/score_view/%s'>查當作績</a>" % obj.pk) list_display = ['customer', 'class_list', score_show] list_display_links = ['customer'] site.register(Student, StudentConfig)
顯示效果:
score_view.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css"> <script src="/static/js/jquery-1.12.4.min.js"></script> </head> <body> <h3>查看{{ student }}成績</h3> <div class="container"> <div class="row"> <div class="col-md-9 col-md-offset-1"> <table class="table table-bordered table-striped"> <thead> <tr> <th>班級</th> <th>班主任</th> <th>任課老師</th> <th>課程成績</th> </tr> </thead> <tbody> {% for cls in class_list %} <tr> {# 班級名稱:class_list.__str__ #} <td>{{ cls }}</td> <td>{{ cls.tutor }}</td> <td> {% for teacher in cls.teachers.all %} <span>{{ teacher }}</span>, {% endfor %} </td> <td> <a class="check_chart"><span>點擊查看</span></a> </td> </tr> {% endfor %} </tbody> </table> </div> </div> </div> </body> </html>
展現效果:
<script> // check_chart綁定事件 $(".check_chart").click(function () { $.ajax({ url: "", // 走當前 type: "get", data:{ sid: $(this).attr("sid"), cid: $(this).attr("cid"), }, success:function (data) { console.log(data); } }) }) </script>
<td> <a class="check_chart" cid="{{ cls.pk }}" sid="{{ student.pk }}"><span>點擊查看</span></a> </td>
其中sid是學生id,cid是班級id。
class StudentConfig(ModelStark): def score_view(self, request, sid): # sid:當前學生的id """擴展視圖""" if request.is_ajax(): # 處理ajax請求 print(request.GET) sid = request.GET.get("sid") cid = request.GET.get("cid") # 去studyrecord查看學生對應課程全部學習記錄 課程須要跨表查詢 study_record_list = StudyRecord.objects.filter(student=sid, course_record__class_obj=cid) else: student = Student.objects.filter(pk=sid).first() class_list = student.class_list.all() # 班級列表 return render(request, "score_view.html", locals())
地址:https://www.hcharts.cn下載程序包後,將壓縮包下code文件夾拷貝到項目crm/static目錄下,並更名爲chart.
在score_view.html中引入highcharts.js:
<head> #省略# <script src="/static/chart/highcharts.js"></script> </head>
<body> <h3>查看{{ student }}成績</h3> <div class="container"...> <div id="container" style="min-width:400px;height:400px"></div> <script> // check_chart綁定事件 $(".check_chart").click(function () { $.ajax({ url: "", // 走當前 type: "get", data: { sid: $(this).attr("sid"), cid: $(this).attr("cid"), }, success: function (data) { // 顯示柱狀圖 var chart = Highcharts.chart('container', { chart: { type: 'column' }, title: { text: '查當作績' }, subtitle: { text: '數據截止 2017-03,來源: <a href="https://en.wikipedia.org/wiki/List_of_cities_proper_by_population">Wikipedia</a>' }, xAxis: { // 橫座標 type: 'category', labels: { rotation: -45 // 設置軸標籤旋轉角度 } }, yAxis: { // 縱座標 min: 0, title: { text: '分數' } }, legend: { enabled: false }, tooltip: { // 鼠標懸浮顯示 pointFormat: '分數: <b>{point.y:.2f}</b>' }, series: [{ name: '成績', data: data, dataLabels: { enabled: true, rotation: -90, color: '#FFFFFF', align: 'right', format: '{point.y:.1f}', // :.1f 爲保留 1 位小數 y: 10 } }] }); } }) }) </script> </body>
from django.http import JsonResponse class StudentConfig(ModelStark): def score_view(self, request, sid): # sid:當前學生的id """擴展視圖""" if request.is_ajax(): # 處理ajax請求 print(request.GET) sid = request.GET.get("sid") cid = request.GET.get("cid") # 去studyrecord查看學生對應課程全部學習記錄 課程須要跨表查詢 study_record_list = StudyRecord.objects.filter(student=sid, course_record__class_obj=cid) data_list = [] for study_record in study_record_list: day_num = study_record.course_record.day_num # 天數 data_list.append(["day%s" % day_num, study_record.score]) # 和highchart的data要求格式相同列表包列表 print(data_list) # [['day1', -1], ['day95', 80]] return JsonResponse(data_list, safe=False) # 序列化不是一個字典必須改成False else: student = Student.objects.filter(pk=sid).first() class_list = student.class_list.all() # 班級列表 return render(request, "score_view.html", locals())
注意要將數據組織爲 [['day94', 100], ['day95', 50], ['day92', 85], ['day91', 90]] 這樣的形式。且使用JsonResponse進行序列化,在系列化的不是一個字典時,須要修改safe=False。