• CRM——讲师与学生


    一、课程记录和学习记录

    1.初始化 course_record, study_record.
    2.学习记录
    3.录入成绩
    4.显示成绩 ajax 查询 柱状图展示成绩 highcharts

    5.上传作业(os模块)
    6.下载作业

    二、配置study_record

    1、给学习记录配置自定义配置

    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对应的是一个元组。

    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批量功能

    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)批量插入操作:

    StudyRecord.objects.bulk_create(temp)
    

    (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别名的配置:

    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中。

    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、添加按钮实现条件过滤查看

    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)
    

      批量调整上课记录为迟到:

      

    六、录入成绩

    1、在课程记录页面添加录入成绩栏(扩展新的url)

    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函数添加录入成绩项目栏

    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)定制录入成绩扩展路由和视图

    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视图函数

    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=" 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>
    score.html

    注意:

    (1)考勤栏显示中文

      针对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>
    

      显示效果:

      

    (2)成绩显示为一个个option对象点选操作

    <td style=" 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渲染批语栏

    <td>
        <textarea name="homework_note" id="" cols="30" rows="4" class="form-control"></textarea>
    </td>
    

      显示效果如下所示:

      

    (4)订制表单和提交按钮

    <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请求

    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=" 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>
    View Code

    (1)分析表单提交的数据

      直接在上面的成绩录入页面提交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",一个键对应三个值,三个值组成数组。导致无法区分谁是谁的成绩和批语。

    (2)修改select标签和textarea标签name生成规则

    <td style=" 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值,可以更好地去录入成绩,完成处理更新操作。

    (3)splice()和rsplice方法

      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']
    """
    

    (4)循环处理reques.POST

    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请求当前页面

    def score(self, request, course_record_id):
        if request.method == "POST":
            """代码省略"""
            return redirect(request.path)  # 拿到当前POST请求路径重定向GET请求
    

    (6)get页面渲染显示之前提交信息为默认值

    <td style=" 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、数据结构调整性能优化

    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)将数据调整为字典套字典的格式

    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)更新数据

    for pk, update_data in data.items():   # 主键、更新数据
        StudyRecord.objects.filter(pk=pk).update(**update_data)
    

      update()方法对于任何结果集均有效,可以同时更新多条记录。

    七、显示成绩 ajax 查询 柱状图展示成绩 highcharts

    1、给学生表定制成绩查询(扩展视图和url)

    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:

    <!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、给点击查看绑定事件

    <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属性

    <td>
        <a class="check_chart" cid="{{ cls.pk }}" sid="{{ student.pk }}"><span>点击查看</span></a>
    </td>
    

      其中sid是学生id,cid是班级id。

    (2)给视图发送ajax,获取学生对应课程的所有学习记录

    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:

    <head>
        #省略#
        <script src="/static/chart/highcharts.js"></script>
    </head>
    

    (2)设计柱状图

      

    (3)将显示柱状图放入ajax中处理

    <body>
    <h3>查看{{ student }}成绩</h3>
    <div class="container"...>
    <div id="container" style="min-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数据

    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、显示效果

      

  • 相关阅读:
    python函数
    python3基础4
    布尔值常识
    字典常用魔法方法
    字典相关常识
    元组相关常识
    列表及其魔法方法(list类中提供的方法)
    列表相关常识
    day11练习题
    字符串相关常识
  • 原文地址:https://www.cnblogs.com/xiugeng/p/9544568.html
Copyright © 2020-2023  润新知