Django + Bootstrap - [echart] Utilisation avancée de graphiques statistiques - statistiques d'augmentation de l'activité quotidienne des utilisateurs, augmentation de l'activité mensuelle et autres données (2)

Introduction

Bootstrapest un framework frontal populaire et ECharts est une bibliothèque de visualisation populaire.
BootstrapIl peut être utilisé pour concevoir des interfaces utilisateur pour des sites Web et des applications, tandis que ECharts peut être utilisé pour créer des graphiques interactifs et visuels.
chart.jsDocumentation chinoise : http://www.bootcss.com/p/chart.js/docs/

2. Utilisation avancée

L'utilisation de base a été présentée dans l'article précédent, lien : https://blog.csdn.net/qq_43030934/article/details/131540606

Cet article est basé sur une utilisation avancée du plug-in Django+bootstrap+echart. L'utilisation de base ne sera pas trop présentée.

2. Rendus

1. Statistiques d'augmentation de l'activité quotidienne

Insérer la description de l'image ici

2. Statistiques de données annuelles et mensuelles

Insérer la description de l'image ici

3. Exemple de code

Fini les bêtises, passons directement au code

1. Front-end

Le code est écrit sur la base de projets liés. Vous pouvez vous y référer en fonction de vos propres projets.

{% extends "base.html" %} {% load static %}

{% block main %}
    {#    <script src="../../../../static/js/echarts-v5.1.2.min.js"></script>#}

    {% if 'is_superuser' in permissions.keys %}
        <!-- daily active users statistics start -->
        <section class="section" style="padding: 100px 0 30px 0">
            <div class="container">
                <div class="row justify-content-center">
                    <div class="col-12 text-center">
                        <div class="section-title mb-2">
                            <h4 class="title mb-4">用户数据统计</h4>
                        </div>
                    </div><!--end col-->
                </div><!--end row-->
                <div class="row mt-4 pt-2 position-relative" id="userDailyData" style="z-index: 1;">
                    <div class="col-lg-7 col-6 mt-4 pt-2">
                        <div class="counter-box text-center">
                            <div id="userDailyIncrease" style="width:auto;height:400px;"></div>
                        </div><!--end counter box-->
                    </div>

                    <div class="col-lg-5 col-6 mt-4 pt-2">
                        <div class="counter-box text-center">
                            <div id="userBaseData" style="width:auto;height:400px;"></div>
                        </div><!--end counter box-->
                    </div>
                </div><!--end row-->
                <div class="feature-posts-placeholder"></div>
            </div><!--end container-->
        </section><!--end section-->
        <!-- daily active users statistics End -->

        <!-- monthly/year increase users statistics start -->
        <section class="section" style="padding: 30px 0 100px 0">
            <div class="container">
                <div class="row mt-4 pt-2 position-relative" style="z-index: 1;">
                    <div class="col-lg-6 col-6 mt-4 pt-2">
                        <div class="counter-box text-center">
                            <div id="userMonthlyIncrease" style="width:auto;height:400px;"></div>
                        </div><!--end counter box-->
                    </div>

                    <div class="col-lg-6 col-6 mt-4 pt-2">
                        <div class="counter-box text-center">
                            <div id="userYearIncrease" style="width:auto;height:400px;"></div>
                        </div><!--end counter box-->
                    </div>
                </div><!--end row-->
                <div class="feature-posts-placeholder"></div>
            </div><!--end container-->
        </section><!--end section-->
        <!-- monthly/year increase users statistics  End -->
    {% endif %}

    <!-- Document change achievement Start -->
    <section class="section  bg-light">
        <div class="container">
            <div class="row mt-4 pt-2 position-relative" id="counter" style="z-index: 1;">
                <div class="col-md col-6 mt-4 pt-2">
                    <div class="counter-box text-center">
                        <img src="{% static 'images/homepage/Asset260.svg' %}" class="avatar avatar-small" alt="">
                        <h2 class="mb-0 mt-4"><span class="counter-value"
                                                    data-count="97">{
   
   { quarterData.requestTotal }}</span></h2>
                        <h6 class="counter-head text-muted">{
   
   { quarterData.currentQuarter }} Change requests</h6>
                    </div><!--end counter box-->
                </div>

                <div class="col-md col-6 mt-4 pt-2">
                    <div class="counter-box text-center">
                        <img src="{% static 'images/homepage/Asset189.svg' %}" class="avatar avatar-small" alt="">
                        <h2 class="mb-0 mt-4"><span class="counter-value"
                                                    data-count="15">{
   
   { quarterData.completed }}</span></h2>
                        <h6 class="counter-head text-muted">Completed</h6>
                    </div><!--end counter box-->
                </div>

                <div class="col-md col-6 mt-4 pt-2">
                    <div class="counter-box text-center">
                        <img src="{% static 'images/homepage/Asset192.svg' %}" class="avatar avatar-small" alt="">
                        <h2 class="mb-0 mt-4"><span class="counter-value"
                                                    data-count="98">{
   
   { quarterData.percentageComplete }}</span>%</h2>
                        <h6 class="counter-head text-muted">Request Complete</h6>
                    </div><!--end counter box-->
                </div>
            </div><!--end row-->
            <div class="feature-posts-placeholder"></div>
        </div><!--end container-->
    </section><!--end section-->
    <!-- Document change achievement End -->
{% endblock %}

{% block script %}
    <script>
        var MyViewVar = {
      
      
            userCurActiveData: {
      
      {
      
       userCurActiveData|safe }},
            usersDataByDaily: {
      
      {
      
       usersDataByDaily|safe }},
            usersDataByMonthly: {
      
      {
      
       usersDataByMonthly|safe }},
            usersDataByYears: {
      
      {
      
       usersDataByYears|safe }},
        }
        console.log(MyViewVar)
        var userDailyIncreaseChart = echarts.init(document.getElementById('userDailyIncrease'));
        userDailyIncreaseChart.setOption({
      
      
            title: {
      
      
                text: '日增日活',
                x: 'center'
            },
            // 图表图例
            legend: {
      
      
                orient: 'vertical',
                data: ['日活用户', '日增用户',],
                left: 'right',
            },
            xAxis: {
      
      
                name: '日',
                type: 'category',
                data: MyViewVar.usersDataByDaily.date_list,
                boundaryGap: false,
                axisLabel: {
      
      
                    inside: false, //刻度标签是否朝内,false朝外
                    interval: 1, // 设置标签全部显示
                    rotate: 30, // 设置标签旋转角度
                    maxInterval: 1000, // 设置刻度间隔
                },
                axisLine: {
      
      
                    lineStyle: {
      
      
                        color: '#333',
                        type: 'solid',
                    },
                }
            },
            yAxis: {
      
      
                name: '数量',
                type: 'value',
                axisLine: {
      
      
                    show: true,    // 是否显示坐标轴轴线
                    lineStyle: {
      
      
                        color: '#333',    // 坐标轴线线的颜色
                        type: 'solid',    // 坐标轴线线的类型(solid实线类型;dashed虚线类型;dotted点状类型)
                    },
                },
            },
            tooltip: {
      
      
                trigger: 'axis',
                axisPointer: {
      
      
                    type: 'cross'
                }
            },
            series: [
                {
      
      
                    name: '日增用户',
                    data: MyViewVar.usersDataByDaily.user_increase_count_list,
                    type: 'line',
                    itemStyle: {
      
      
                        color: '#91CC75',
                    },
                    markPoint: {
      
      
                        data: [
                            {
      
      type: 'max', name: '最大值'},
                            {
      
      type: 'min', name: '最小值'}
                        ]
                    },
                    lineStyle: {
      
      
                        color: '#91CC75', //线颜色
                        type: 'solid', //线的类型
                        opacity: 0.8, //线透明度
                        shadowBlur: 5, //阴影模糊度
                        shadowColor: '#999', //阴影颜色
                        shadowOffsetX: 2, //阴影X轴偏移量
                        shadowOffsetY: 2, //阴影Y轴偏移量
                        radius: 100 //曲线圆角半径
                    },
                },
                {
      
      
                    name: '日活用户',
                    type: 'line',
                    data: MyViewVar.usersDataByDaily.user_active_count_list,
                    itemStyle: {
      
      
                        color: '#FFC858',
                    },
                    markPoint: {
      
      
                        data: [
                            {
      
      type: 'max', name: '最大值'},
                            {
      
      type: 'min', name: '最小值'}
                        ]
                    },
                    lineStyle: {
      
      
                        color: '#FFC858', //线颜色
                    },
                },
            ]
        });

        var userBaseDataChart = echarts.init(document.getElementById('userBaseData'));
        //定义饼图数据
        var data = [
            {
      
      value: MyViewVar.userCurActiveData.dailyActiveCount, name: '日活用户'},
            {
      
      value: MyViewVar.userCurActiveData.monthlyActiveCount, name: '月活用户'},
        ];
        //定义饼图配置项
        var option = {
      
      
            title: {
      
      
                text: '用户当日及当月活跃人数\n' + '用户总人数:' + MyViewVar.userCurActiveData.totalCount,
                x: 'center'
            },
            tooltip: {
      
      
                trigger: 'item',
                formatter: "{a} <br/>{b} : {c}<br/>" + "用户总人数:" + MyViewVar.userCurActiveData.totalCount
            },
            legend: {
      
      
                orient: 'vertical',
                left: 'right',
                data: ['日活用户', '月活用户']
            },
            series: [
                {
      
      
                    name: '用户基础数据统计',
                    type: 'pie',
                    radius: ['40%', '60%'],
                    center: ['50%', '60%'],
                    data: data,
                    label: {
      
      
                        show: true,
                        formatter: function (params) {
      
      
                            // 计算总数
                            var total = MyViewVar.userCurActiveData.totalCount;
                            // 显示数据项名称和百分比
                            return params.name + '\n' + params.value + '人' + '\n' + (params.value / total * 100).toFixed(2) + '%';
                        }
                    },
                    itemStyle: {
      
      
                        emphasis: {
      
      
                            shadowBlur: 10,
                            shadowOffsetX: 0,
                            shadowColor: 'rgba(0, 0, 0, 0.5)'
                        }
                    },
                    color: ['#FF8D5D', '#FFC858']
                }
            ]
        };
        //渲染饼图
        userBaseDataChart.setOption(option);

        var userMonthlyIncreaseChart = echarts.init(document.getElementById('userMonthlyIncrease'));
        userMonthlyIncreaseChart.setOption({
      
      
            title: {
      
      
                text: '月增月活',
                x: 'center'
            },
            // 图表图例
            legend: {
      
      
                data: ['月活用户', '月增用户'],
                left: 'right',
            },
            xAxis: {
      
      
                name: '月',
                type: 'category',
                data: MyViewVar.usersDataByMonthly.month_list,
                boundaryGap: false,
                axisLabel: {
      
      
                    inside: false, //刻度标签是否朝内,false朝外
                    interval: 0, // 设置标签全部显示
                    rotate: 30, // 设置标签旋转角度
                    maxInterval: 1000, // 设置刻度间隔
                },
                axisLine: {
      
      
                    lineStyle: {
      
      
                        color: '#333',
                        type: 'solid',
                    },
                },
            },
            yAxis: {
      
      
                name: '数量',
                type: 'value',
                axisLine: {
      
      
                    show: true,    // 是否显示坐标轴轴线
                    lineStyle: {
      
      
                        color: '#333',    // 坐标轴线线的颜色
                        type: 'solid',    // 坐标轴线线的类型(solid实线类型;dashed虚线类型;dotted点状类型)
                    },
                },
            },
            tooltip: {
      
      
                trigger: 'axis',
            },
            series: [
                {
      
      
                    name: '月活用户',
                    type: 'line',
                    data: MyViewVar.usersDataByMonthly.user_active_count_list,
                    itemStyle: {
      
      
                        color: '#FFC858',
                    },
                    markPoint: {
      
      
                        data: [
                            {
      
      type: 'max', name: '最大值'},
                            {
      
      type: 'min', name: '最小值'}
                        ]
                    },
                    lineStyle: {
      
      
                        color: '#FFC858', //线颜色
                    },
                },
                {
      
      
                    name: '月增用户',
                    data: MyViewVar.usersDataByMonthly.user_increase_count_list,
                    type: 'line',
                    itemStyle: {
      
      
                        color: '#91CC75',
                    },
                    label: {
      
      
                        show: true,
                        formatter: function (params) {
      
      
                            return params.value;
                        }
                    },
                    markPoint: {
      
      
                        data: [
                            {
      
      type: 'max', name: '最大值'},
                            {
      
      type: 'min', name: '最小值'}
                        ]
                    },
                    lineStyle: {
      
      
                        color: '#91CC75', //线颜色
                    },
                },
            ]
        });

        var userYearIncreaseChart = echarts.init(document.getElementById('userYearIncrease'));
        userYearIncreaseChart.setOption({
      
      
            title: {
      
      
                text: '用户年增长及跃人数\n' + '用户总人数:' + MyViewVar.userCurActiveData.totalCount,
                x: 'center'
            },
            tooltip: {
      
      },
            legend: {
      
      
                orient: 'vertical',
                data: ['年活跃用户', '年增长用户'],
                left: 'right',
            },
            xAxis: {
      
      
                axisLine: {
      
      
                    show: true,    // 是否显示坐标轴轴线
                    lineStyle: {
      
      
                        color: '#333',    // 坐标轴线线的颜色
                        type: 'solid',    // 坐标轴线线的类型(solid实线类型;dashed虚线类型;dotted点状类型)
                    },
                },
                data: MyViewVar.usersDataByYears.year_list,
            },
            yAxis: {
      
      
                name: '数量',
                type: 'value',
                axisLine: {
      
      
                    show: true,    // 是否显示坐标轴轴线
                    lineStyle: {
      
      
                        color: '#333',    // 坐标轴线线的颜色
                        type: 'solid',    // 坐标轴线线的类型(solid实线类型;dashed虚线类型;dotted点状类型)
                    },
                },
            },
            series: [
                {
      
      
                    name: '年活跃用户',
                    type: 'bar',
                    data: MyViewVar.usersDataByYears.user_active_count_list,
                    itemStyle: {
      
      
                        color: '#FFC858',
                    },
                },
                {
      
      
                    name: '年增长用户',
                    type: 'bar',
                    data: MyViewVar.usersDataByYears.user_increase_count_list,
                },

            ],
            label: {
      
      
                show: true,
                position: 'top',  // 在柱形顶部显示标签
                formatter: '{c}',  // 数值显示格式
                color: '#000',  // 标签颜色
                fontSize: 14,  // 标签字体大小
            },
        })
    </script>
{% endblock %}

2. Code back-end

La pile technologique utilisée par l'interface de code back-end est. Django+ORM
Le code est à titre de référence uniquement. Vous pouvez l'utiliser comme référence en fonction de l'activité de votre propre projet.

class DataStatisticsView(LoginRequiredJSONMixin, APIView):

    def get(self, request):
        permissions = get_user_permissions(request.user.id)

        quarterData = get_quarter_data_statistics(CP_Register)

        # 获取当前日期
        now_date = datetime.date.today()
        userCurActiveData = self.get_cur_user_active_data(now_date)
        usersDataByDaily = self.get_increase_and_active_users_by_daily(now_date)
        usersDataByMonthly = self.get_increase_and_active_users_by_monthly(now_date)
        usersDataByYears = self.get_increase_and_active_users_by_years(now_date)

        context = {
    
    
            'permissions': permissions,
            'quarterData': quarterData,
            'userCurActiveData': userCurActiveData,
            'usersDataByDaily': usersDataByDaily,
            'usersDataByMonthly': usersDataByMonthly,
            'usersDataByYears': usersDataByYears,
        }
        return render(request, 'teams/my_dashboard/statistics/data_statistics.html', context)

    def get_increase_and_active_users_by_years(self, now_date):
        """数据库中按年增长及年活跃人数"""
        # 按年增长统计用户
        users_per_year = User.objects.annotate(year=ExtractYear('date_joined')).values('year').annotate(
            total=Count('id'))
        user_increase_count_list = []
        year_list = []
        for user in users_per_year:
            user_increase_count_list.append(user['total'])
            year_list.append(user['year'])

        # 按年统计活跃人数
        users_per_year = User.objects.annotate(year=ExtractYear('last_login')).values('year').annotate(
            total=Count('id'))
        user_active_count_list = []
        for user in users_per_year:
            user_active_count_list.append(int(user['total']) * ActiveCoefficient.year_active)

        usersDataByYears = {
    
    
            'user_increase_count_list': user_increase_count_list,
            'user_active_count_list': user_active_count_list,
            'year_list': year_list,
        }

        return usersDataByYears

    def get_increase_and_active_users_by_monthly(self, now_date):
        """
        近一年用户月增及月活跃数据
        sqlite按当月统计一年用户的数量sql:SELECT DATE('now', 'start of month') AS end_date,
                                    DATE('now', '-12 months', 'start of month') AS start_date;
                                    SELECT strftime('%Y-%m', date_joined) AS month,
                                           COUNT(id) AS count
                                    FROM auth_user
                                    WHERE date_joined >= DATE('now', '-12 months', 'start of month')
                                    GROUP BY month
                                    ORDER BY month;
        """
        user_increase_count_list = []
        user_active_count_list = []
        month_list = []

        # FIXME--bug:某月用户数量为0时无数据
        """
        end_date = now_date.replace(day=30)
        start_date = (end_date - datetime.timedelta(days=365)).replace(day=1)

        {'user_count_list': [33, 37, 30, 35, 25, 22, 11, 35, 4, 6, 1, 7], 
         'month_list': ['22-07', '22-08', '22-09', '22-10', '22-11', '22-12', '23-01', '23-02', '23-03', '23-04', '23-05', '23-07']
         }
        users_last_year = User.objects.filter(date_joined__range=(start_date, end_date)).annotate(
            month=TruncMonth('date_joined')).values('month').annotate(count=Count('id'))
        for user in users_last_year:
            user_count_list.append(user['count'])
            month_list.append(user['month'].strftime('%y-%m'))
        """

        # 计算往前12个月的日期时间,计算月增月活数据
        for i in range(12):
            # 当月起始时间和月末时间
            month_first_day = (now_date - datetime.timedelta(days=365 * i / 12)).replace(day=1)
            month_last_day = (month_first_day + datetime.timedelta(days=32)).replace(day=1) - datetime.timedelta(days=1)
            month_increase_count = User.objects.filter(date_joined__range=(month_first_day, month_last_day)).count()
            month_list.append(month_first_day.strftime('%y-%m'))
            user_increase_count_list.append(month_increase_count)
            moth_active_count = int(User.objects.filter(
                last_login__range=(month_first_day, month_last_day)).count() * ActiveCoefficient.monthly_active)
            user_active_count_list.append(moth_active_count)

        usersDataByMonthly = {
    
    
            'user_increase_count_list': user_increase_count_list[::-1],
            'user_active_count_list': user_active_count_list[::-1],
            'month_list': month_list[::-1],
        }

        return usersDataByMonthly

    def get_increase_and_active_users_by_daily(self, now_date):
        """近一月用户日增日活数据"""
        # 获取一个月前日期
        start_date = now_date - datetime.timedelta(days=30)
        date_list = []
        user_increase_count_list = []
        user_active_count_list = []
        for i in range(1, 31):
            # 循环遍历获取当天日期
            cur_date = start_date + datetime.timedelta(days=i)
            next_date = start_date + datetime.timedelta(days=i + 1)
            day_increase_count = User.objects.filter(last_login__range=(cur_date, next_date)).count()
            date_list.append(cur_date.strftime('%y-%m-%d'))
            user_increase_count_list.append(day_increase_count)
            day_active_count = int(
                User.objects.filter(last_login__range=(cur_date, next_date)).count() * ActiveCoefficient.daily_active)
            user_active_count_list.append(day_active_count)

        dailyIncreaseUsers = {
    
    
            'date_list': date_list,
            'user_increase_count_list': user_increase_count_list,
            'user_active_count_list': user_active_count_list,
        }

        return dailyIncreaseUsers

    def get_cur_user_active_data(self, now_date):
        """当日及当月活跃数据"""
        # 日活用户
        dailyActiveCount = User.objects.filter(last_login__gte=now_date).count()
        # 月活用户
        first_day_of_month = datetime.date(now_date.year, now_date.month, 1)
        last_day_of_month = datetime.date(now_date.year, now_date.month + 1, 1) - datetime.timedelta(days=1)
        monthlyActiveCount = User.objects.filter(last_login__range=(first_day_of_month, last_day_of_month)).count()
        # 用户总数
        totalCount = User.objects.all().count()

        userCurActiveData = {
    
    
            'dailyActiveCount': int(dailyActiveCount * ActiveCoefficient.daily_active),
            'monthlyActiveCount': int(monthlyActiveCount * ActiveCoefficient.monthly_active),
            'totalCount': totalCount,
            'date': now_date.strftime('%Y-%m-%d'),
        }
        return userCurActiveData

utils.py

class ActiveCoefficient:
    daily_active = 1.5
    monthly_active = 1.5
    year_active = 3

def get_user_permissions(user_id):
    from registration.models import UserProfile

    u_pro = UserProfile.objects.filter(user_id=user_id).first()
    permissions = OrderedDict()
    if u_pro.is_superuser:
        permissions['is_superuser'] = '超级管理员'
    if u_pro.is_team_leader:
        permissions['is_team_leader'] = '团队负责人'
    if u_pro.is_ele_feature_extension_admin:
        permissions['ele_feature_extension_admin'] = '普通管理员'
    if u_pro.is_es_feature_extension_admin:
        permissions['es_feature_extension_admin'] = '普通管理员'

    if u_pro.role:
        permissions = get_role_permission(u_pro.role.id, permissions)
    return permissions

def get_quarter_data_statistics(obj):
    """季度发布数据统计"""

    today = datetime.date.today()
    current_quarter = (today.month - 1) // 3 + 1
    # 当前年份季度
    current_year_quarter = str(today.year) + 'Q{}'.format(str(current_quarter))
    total = obj.objects.filter(schedule__startswith=current_year_quarter).count()
    completed_cnt = obj.objects.filter(schedule__startswith=current_year_quarter).filter(
        Q(decision__in=['', 'Released']) | Q(decision__isnull=True)).count()
    try:
        percentageComplete = int(completed_cnt / total * 100)
    except Exception as e:
        percentageComplete = 0
        logger.info('homePage error :{}'.format(e))
    QuarterData = {
    
    
        'requestTotal': total,
        'percentageComplete': percentageComplete,
        'completed': completed_cnt,
        'currentQuarter': 'Q{}'.format(current_quarter),
    }
    return QuarterData

Ce qui précède est l'utilisation avancée de Django + Bootstrap - [echart] graphiques statistiques - l'utilisation de base de données statistiques telles que l'augmentation quotidienne de l'activité quotidienne des utilisateurs, l'augmentation mensuelle de l'activité mensuelle, etc. J'espère que cela vous sera utile !

Je suppose que tu aimes

Origine blog.csdn.net/qq_43030934/article/details/131769391
conseillé
Classement