CRM——讲师与学生
一、课程记录和学习记录
1.初始化 course_record, study_record.
2.学习记录
3.录入成绩
4.显示成绩 ajax 查询 柱状图展示成绩 highcharts
5.上传作业(os模块)
6.下载作业
二、配置study_record
1、给学习记录配置自定义配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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取存的值对应的中文。
2、修改ModelStark中get_body方法全局处理记录对象包含choices情况
在models中choices对应的是一个元组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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) |
录入学习记录:
三、批量生成学习记录
1、定制CourseRecod批量功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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) |
注意
(1)批量插入操作:
1 | StudyRecord.objects.bulk_create(temp) |
(2)跨表查询班级所有的学生
1 2 | # 过滤出班级所有的学生 学生表classlist关联班级表 student_list = Student.objects. filter (class_list__id = course_record.class_obj.pk) # 学生的班级id和课程记录班级的id进行比对 拿到班级所有的学生 |
过滤course_record关联的班级对应的所有的学生。
(3)批量操作别名描述short_description
这是由于在Modelstark中源码get_action_list有关于action别名的配置:
1 2 3 4 5 6 7 8 9 | 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 |
2、批量生成学习记录
学习记录生产成功:
四、学习记录筛选查看
1、studyrecord/?course_record=%s过滤
根据课程记录来过滤学习记录,这个需要修改service/stark.py中的get_filter_condition。因为这个其实也是一种filter过滤,但并没有写在filter_list中。
1 2 3 4 5 6 7 8 9 10 11 | 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拿到过滤结果:
2、添加按钮实现条件过滤查看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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) |
课程记录页面:
点击记录跳转学习记录页面:
五、考勤点名
给学习记录订制迟到批量操作
1 2 3 4 5 6 7 8 9 | 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) |
批量调整上课记录为迟到:
六、录入成绩
1、在课程记录页面添加录入成绩栏(扩展新的url)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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): """代码省略""" |
注意:
(1)定制record_score函数添加录入成绩项目栏
1 2 3 4 5 | 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) |
(2)定制录入成绩扩展路由和视图
1 2 3 4 5 6 7 8 | 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 |
(3)测试验证
点击录入成绩,跳转对应页面:
2、处理score视图函数
1 2 3 4 5 6 | 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字段内容传递给模板
3、构建录入成绩页面

<!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>
注意:
(1)考勤栏显示中文
针对Model中的record字段:
1 | record = models.CharField( "上课纪录" , choices = record_choices, default = "checked" , max_length = 64 ) |
要显示迟到签到信息需要拼接get和display取值
1 2 | {# < td >{{ study_record.record }}</ td > 针对带有choices的字段使用拼接get和display #} < td >{{ study_record.get_record_display }}</ td > |
显示效果:
(2)成绩显示为一个个option对象点选操作
1 2 3 4 5 6 7 | <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拿到元组第二个值即评分等级。显示效果如下:
(3)用textarea渲染批语栏
1 2 3 | <td> <textarea name = "homework_note" id = " " cols=" 30 " rows=" 4 " class=" form - control">< / textarea> < / td> |
显示效果如下所示:
(4)订制表单和提交按钮
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | < 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 > |
显示效果:
4、视图函数处理post请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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>
(1)分析表单提交的数据
直接在上面的成绩录入页面提交POST请求:
在视图中接收POST请求,打印接收的request.POST数据:
1 2 3 4 5 6 7 8 9 | 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",一个键对应三个值,三个值组成数组。导致无法区分谁是谁的成绩和批语。
(2)修改select标签和textarea标签name生成规则
1 2 3 4 5 6 7 8 9 10 | < 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获取的数据如下:
1 2 3 4 5 | 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值,可以更好地去录入成绩,完成处理更新操作。
(3)splice()和rsplice方法
Python split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则仅分隔 num 个子字符串。
1 2 3 4 5 6 7 8 | 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'] """ |
(4)循环处理reques.POST
1 2 3 4 5 6 7 8 9 | 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) |
(5)重定向到POST请求当前页面
1 2 3 4 | def score( self , request, course_record_id): if request.method = = "POST" : """代码省略""" return redirect(request.path) # 拿到当前POST请求路径重定向GET请求 |
(6)get页面渲染显示之前提交信息为默认值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <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请求获取的当前页面,页面保留之前录入的数据。
5、数据结构调整性能优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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请求 |
(1)将数据调整为字典套字典的格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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'}} |
(2)更新数据
1 2 | for pk, update_data in data.items(): # 主键、更新数据 StudyRecord.objects. filter (pk = pk).update( * * update_data) |
update()方法对于任何结果集均有效,可以同时更新多条记录。
七、显示成绩 ajax 查询 柱状图展示成绩 highcharts
1、给学生表定制成绩查询(扩展视图和url)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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) |
显示效果:
2、成绩展示模板设计
score_view.html:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | <! 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 > |
展示效果:
3、给点击查看绑定事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <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> |
(1)给点击查看a标签添加sid和cid属性
1 2 3 | < td > < a class="check_chart" cid="{{ cls.pk }}" sid="{{ student.pk }}">< span >点击查看</ span ></ a > </ td > |
其中sid是学生id,cid是班级id。
(2)给视图发送ajax,获取学生对应课程的所有学习记录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 ()) |
4、使用highchart插件显示成绩
(1)下载引入highchart
地址:https://www.hcharts.cn下载程序包后,将压缩包下code文件夹拷贝到项目crm/static目录下,并改名为chart.
在score_view.html中引入highcharts.js:
1 2 3 4 | < head > #省略# < script src="/static/chart/highcharts.js"></ script > </ head > |
(2)设计柱状图
(3)将显示柱状图放入ajax中处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | <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> |
5、在视图处理出highcharts模板要求的data数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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。
6、显示效果
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术