Flask构建微信订餐小程序②-全站统计

第15章 统计管理模块开发

15-1 定时器统计入口模型 + 会员统计功能 (runserver 添加命令)

from application import app, manager, db
from application import app, manager
from flask_script import Server
from jobs.launcher import runjob
from flask_migrate import Migrate, MigrateCommand
import www

# python manage.py runserver
manager.add_command('runserver', Server(host='0.0.0.0', port=app.config['SERVER_PORT'], use_debugger=True, use_reloader=True))

# database migrate comand
"""
    python manage.py db init
    python manage.py db migrate
    python manage.py db upgrade
"""
Migrate(app, db)
manager.add_command('db', MigrateCommand)


# web server
manager.add_command('runserver', Server(
    # host='0.0.0.0',
    port=app.config['SERVER_PORT'],
    use_debugger=True
))
# job entrance
manager.add_command('runjob', runjob())


def main():
    manager.run()


if __name__ == '__main__':
    try:
        import sys

        sys.exit(main())
    except Exception as e:
        import traceback

        traceback.print_exc()  # 打印错误

# -*- coding: utf-8 -*-


from application import app, manager
from flask_script import Command, Option
import sys, argparse, traceback

"""
python manage.py runjob -m Test  (  jobs/tasks/Test.py )
python manage.py runjob -m test/Index (  jobs/tasks/test/Index.py )
* name or flags - 名称或选项字符串列表, e.g. foo or -f, --foo.
* action - 参数如果定义了选项,表示这是一个操作参数,至于调用时做哪种操作由用户输入或者default决定。
* nargs - 应该使用的命令行参数数。.
* const - 某些动作或参数个数的常数值。.
* default - 如果命令行没有对输入这个参数相应的值,则此参数用default给出的值.
* type -将用户输入的值转化为哪种类型.
* choices - 参数可输入值的范围或选择.
* required - 命令行输入的值是否可以被忽略(布尔量).
* help - 参数的简要描述.
* metavar - useage中显示的参数的名称.
* dest - 要添加到解析参数返回的对象中的属性的名称.
"""


class runjob(Command):
    """
    运行job
    """

    help = description = 'Runs the job'
    capture_all_args = True

    def run(self, *args, **kwargs):
        args = sys.argv[2:]
        parser = argparse.ArgumentParser(add_help=True)

        parser.add_argument("-m", "--name", dest="name", metavar="name", help="指定job名", required=True)
        parser.add_argument("-a", "--act", dest="act", metavar="act", help="Job动作", required=False)
        parser.add_argument("-p", "--param", dest="param", nargs="*", metavar="param", help="业务参数", default='',
                            required=False)
        params = parser.parse_args(args)
        params_dict = params.__dict__
        ret_params = {}
        for item in params_dict.keys():
            ret_params[item] = params_dict[item]

        if "name" not in ret_params or not ret_params['name']:
            return self.tips()

        module_name = ret_params['name'].replace("/", ".")
        try:
            import_string = "from jobs.tasks.%s import JobTask as job_target" % (module_name)
            # exec(source, globals=None, locals=None, /)动态执行Python代码
            exec(import_string, globals())
            target = job_target()
            target.run(ret_params)
        except Exception as e:
            traceback.print_exc()

    def tips(self):
        tip_msg = '''
            请正确调度Job
            python manage runjob -m Test  (  jobs/tasks/Test.py )
            python manage runjob -m test/Index (  jobs/tasks/test/Index.py )
            python manage.py runjob -m stat/daily -a site -p 2020-03-22    # 全站统计
        '''
        app.logger.info(tip_msg)
        return False

15-2 会员、商品售卖统计任务

# -*- coding: utf-8 -*-
import random, datetime
from sqlalchemy import func
from application import app, db
from common.models.member.Member import Member
from common.models.food.food import Food
from common.libs.Helper import getFormatDate, getCurrentDate
from common.models.food.food_sale_change_log import FoodSaleChangeLog
from common.models.food.WxShareHistory import WxShareHistory
from common.models.pay.pay_order import PayOrder
from common.models.stat.stat_daily_food import StatDailyFood
from common.models.stat.stat_daily_member import StatDailyMember
from common.models.stat.stat_daily_site import StatDailySite

"""
python manager.py runjob -m stat/daily -a member|food|site/test -p 2018-07-01
"""


class JobTask():
    def __init__(self):
        pass

    def run(self, params):
        act = params['act'] if 'act' in params else ''
        date = params['param'][0] if params['param'] and len(params['param']) else getFormatDate(format="%Y-%m-%d")
        if not act:
            return

        date_from = date + " 00:00:00"
        date_to = date + " 23:59:59"
        func_params = {
            'act': act,
            'date': date,
            'date_from': date_from,
            'date_to': date_to
        }
        if act == "member":
            self.statMember(func_params)
        elif act == "food":
            self.statFood(func_params)
        elif act == "site":
            self.statSite(func_params)
        elif act == "test":
            self.test()

        app.logger.info("it's over~~")
        return

    def statMember(self, params):
        """
        会员统计
        :param params:
        :return:
        """
        act = params['act']
        date = params['date']
        date_from = params['date_from']
        date_to = params['date_to']
        app.logger.info("act:{0},from:{1},to:{2}".format(act, date_from, date_to))

        member_list = Member.query.all()
        if not member_list:
            app.logger.info("no member list")
            return

        for member_info in member_list:
            tmp_stat_member = StatDailyMember.query.filter_by(date=date, member_id=member_info.id).first()
            if tmp_stat_member:
                tmp_model_stat_member = tmp_stat_member
            else:
                tmp_model_stat_member = StatDailyMember()
                tmp_model_stat_member.date = date
                tmp_model_stat_member.member_id = member_info.id

            tmp_stat_pay = db.session.query(func.sum(PayOrder.total_price).label("total_pay_money")) \
                .filter(PayOrder.member_id == member_info.id, PayOrder.status == 1) \
                .filter(PayOrder.created_time >= date_from, PayOrder.created_time <= date_to).first()

            tmp_stat_share_count = WxShareHistory.query.filter(PayOrder.member_id == member_info.id) \
                .filter(PayOrder.created_time >= date_from, PayOrder.created_time <= date_to).count()
            #  当日分享总次数
            tmp_model_stat_member.total_shared_count = tmp_stat_share_count
            #  当日付款总金额
            tmp_model_stat_member.total_pay_money = tmp_stat_pay[0] if tmp_stat_pay[0] else 0.00
            tmp_model_stat_member.created_time = getCurrentDate()
            '''
            为了测试效果模拟数据
            '''
            tmp_model_stat_member.total_shared_count = random.randint(50, 100)
            tmp_model_stat_member.total_pay_money = random.randint(1000, 1010)
            tmp_model_stat_member.updated_time = getCurrentDate()
            db.session.add(tmp_model_stat_member)
            db.session.commit()

        return

    def statFood(self, params):
        """
        food统计
        :param params:
        :return:
        """
        act = params['act']
        date = params['date']
        date_from = params['date_from']
        date_to = params['date_to']
        app.logger.info("act:{0},from:{1},to:{2}".format(act, date_from, date_to))

        stat_food_list = db.session.query(FoodSaleChangeLog.food_id,
                                          func.sum(FoodSaleChangeLog.quantity).label("total_count"),
                                          func.sum(FoodSaleChangeLog.price).label("total_pay_money")) \
            .filter(FoodSaleChangeLog.created_time >= date_from, FoodSaleChangeLog.created_time <= date_to) \
            .group_by(FoodSaleChangeLog.food_id).all()

        if not stat_food_list:
            app.logger.info("no data")
            return

        for item in stat_food_list:
            tmp_food_id = item[0]
            tmp_stat_food = StatDailyFood.query.filter_by(date=date, food_id=tmp_food_id).first()
            if tmp_stat_food:
                tmp_model_stat_food = tmp_stat_food
            else:
                tmp_model_stat_food = StatDailyFood()
                tmp_model_stat_food.date = date
                tmp_model_stat_food.food_id = tmp_food_id
                tmp_model_stat_food.created_time = getCurrentDate()
            #  售卖总数量
            tmp_model_stat_food.total_count = item[1]
            #  总售卖金额
            tmp_model_stat_food.total_pay_money = item[2]
            tmp_model_stat_food.updated_time = getCurrentDate()

            '''
            为了测试效果模拟数据
            '''
            tmp_model_stat_food.total_count = random.randint(50, 100)
            tmp_model_stat_food.total_pay_money = random.randint(1000, 1010)
            db.session.add(tmp_model_stat_food)
            db.session.commit()

        return

15-3 全站统计任务和历史数据初始化技巧

    def statSite(self, params):
        """
        site全站统计
        :param params:
        :return:
        """
        act = params['act']
        date = params['date']
        date_from = params['date_from']
        date_to = params['date_to']
        app.logger.info("act:{0},from:{1},to:{2}".format(act, date_from, date_to))

        stat_pay = db.session.query(func.sum(PayOrder.total_price).label("total_pay_money")) \
            .filter(PayOrder.status == 1) \
            .filter(PayOrder.created_time >= date_from, PayOrder.created_time <= date_to).first()

        stat_member_count = Member.query.count()
        stat_new_member_count = Member.query.filter(Member.created_time >= date_from,
                                                    Member.created_time <= date_to).count()

        stat_order_count = PayOrder.query.filter_by(status=1) \
            .filter(PayOrder.created_time >= date_from, PayOrder.created_time <= date_to) \
            .count()

        stat_share_count = WxShareHistory.query.filter(WxShareHistory.created_time >= date_from
                                                       , WxShareHistory.created_time <= date_to).count()

        tmp_stat_site = StatDailySite.query.filter_by(date=date).first()
        if tmp_stat_site:
            tmp_model_stat_site = tmp_stat_site
        else:
            tmp_model_stat_site = StatDailySite()
            tmp_model_stat_site.date = date
            tmp_model_stat_site.created_time = getCurrentDate()
        #  当日应收总金额
        tmp_model_stat_site.total_pay_money = stat_pay[0] if stat_pay[0] else 0.00
        #  会员总数
        tmp_model_stat_site.total_new_member_count = stat_new_member_count
        #  当日新增会员数
        tmp_model_stat_site.total_member_count = stat_member_count
        #  当日订单数
        tmp_model_stat_site.total_order_count = stat_order_count
        #  当日分享数
        tmp_model_stat_site.total_shared_count = stat_share_count
        tmp_model_stat_site.updated_time = getCurrentDate()
        '''
        为了测试效果模拟数据
        '''
        tmp_model_stat_site.total_pay_money = random.randint(1000, 1010)
        tmp_model_stat_site.total_new_member_count = random.randint(50, 100)
        tmp_model_stat_site.total_member_count += tmp_model_stat_site.total_new_member_count
        tmp_model_stat_site.total_order_count = random.randint(900, 1000)
        tmp_model_stat_site.total_shared_count = random.randint(1000, 2000)
        db.session.add(tmp_model_stat_site)
        db.session.commit()

    def test(self):
        now = datetime.datetime.now()
        for i in reversed(range(1, 30)):
            date_before = now + datetime.timedelta(days=-i)
            date = getFormatDate(date=date_before, format="%Y-%m-%d")
            tmp_params = {
                'act': 'test',
                'date': date,
                'date_from': date + " 00:00:00",
                'date_to': date + " 23:59:59"
            }
            self.testFood(date)
            self.statFood(tmp_params)
            self.statMember(tmp_params)
            self.statSite(tmp_params)

    def testFood(self, date):
        list = Food.query.all()
        if list:
            for item in list:
                model = FoodSaleChangeLog()
                model.food_id = item.id
                model.quantity = random.randint(1, 10)
                model.price = model.quantity * item.price
                model.member_id = 1
                model.created_time = date + " " + getFormatDate(format="%H:%M:%S")
                db.session.add(model)
                db.session.commit()

15-4 仪表板统计数据展示

# -*- coding: utf-8 -*-

import datetime
from flask import Blueprint
from common.libs.Helper import ops_render, getFormatDate
from common.models.stat.stat_daily_site import StatDailySite

route_index = Blueprint('index_page', __name__)


@route_index.route('/')
def index():
    resp_data = {
        'data': {
            'finance': {
                'today': 0,
                'month': 0
            },
            'member': {
                'today_new': 0,
                'month_new': 0,
                'total': 0
            },
            'order': {
                'today': 0,
                'month': 0
            },
            'shared': {
                'today': 0,
                'month': 0
            },
        }
    }

    now = datetime.datetime.now()
    date_before_30days = now + datetime.timedelta(days=-30)
    date_from = getFormatDate(date=date_before_30days, format="%Y-%m-%d")
    date_to = getFormatDate(date=now, format="%Y-%m-%d")

    list = StatDailySite.query.filter(StatDailySite.date >= date_from) \
        .filter(StatDailySite.date <= date_to).order_by(StatDailySite.id.asc()) \
        .all()
    data = resp_data['data']
    if list:

        for item in list:
            data['finance']['month'] += item.total_pay_money
            data['member']['month_new'] += item.total_new_member_count
            data['member']['total'] = item.total_member_count
            data['order']['month'] += item.total_order_count
            data['shared']['month'] += item.total_shared_count
            if getFormatDate(date=item.date, format="%Y-%m-%d") == date_to:
                data['finance']['today'] = item.total_pay_money
                data['member']['today_new'] = item.total_new_member_count
                data['order']['today'] = item.total_order_count
                data['shared']['today'] = item.total_shared_count

    return ops_render("index/index.html", resp_data)

数据库反向生成ORM模型

flask-sqlacodegen "mysql://root:123456@localhost:3306/movie" --tables movie_daily_member --outfile "member.py"  --flask

在这里插入图片描述

第15章 统计管理模块开发 - hcharts

{% extends 'admin/admin.html' %}
{% block content %}
<section class="content-header">
    <h1>某柠檬管理系统</h1>
    <ol class="breadcrumb">
        <li><a href="#"><i class="fa fa-dashboard"></i> 首页</a></li>
        <li class="active">网站统计</li>
    </ol>
</section>
<!--    <div id="page-wrapper" class="gray-bg" style="background-color: #ffffff;">-->
<section class="content" id="showcontent">
    <div class="wrapper wrapper-content">
    </div>


    <div class="row">
        <div class="col-lg-1">
        </div>
        <div class="col-lg-3">
            <div class="ibox float-e-margins">
                <div class="ibox-title">
                    <span class="label label-primary pull-right">日统计</span>
                    <h5>播放概况</h5>
                </div>
                <div class="ibox-content">
                    <h1 class="no-margins">{{ data.play.today }}</h1>
                    <small>播放总数:{{ data.play.total }}</small>
                    <small>近30日:{{ data.play.month }}</small>
                </div>
            </div>
        </div>
        <div class="col-lg-3">
            <div class="ibox float-e-margins">
                <div class="ibox-title">
                    <span class="label label-primary pull-right">日统计</span>
                    <h5>会员</h5>
                </div>
                <div class="ibox-content">
                    <h1 class="no-margins">{{ data.member.today_new }}</h1>
                    <small>会员总数:{{ data.member.total }}</small>
                    <small>近30日新增:{{ data.member.month_new }}</small>
                </div>
            </div>
        </div>

        <div class="col-lg-3">
            <div class="ibox float-e-margins">
                <div class="ibox-title">
                    <span class="label label-primary pull-right">日统计</span>
                    <h5>评论</h5>
                </div>
                <div class="ibox-content">
                    <h1 class="no-margins">{{ data.comment.today }}</h1>
                    <small>近30日新增:{{ data.comment.month }}</small>
                </div>
            </div>
        </div>
    </div>

    <div class="row">
        <div class="col-lg-12" id="member_order" style="height: 400px;border: 1px solid #e6e6e6;padding-top: 20px;">
            使用highchart画图
        </div>
        <div class="col-lg-12" id="finance" style="height: 400px;border: 1px solid #e6e6e6;padding-top: 20px;">
            使用highchart画图
        </div>
    </div>
    </div>
</section>
{% endblock %}
{% block js %}


<!--<script src="{{ url_for('static',filename='plugins/jquery-2.1.1.js') }}"></script>-->
<script src="{{ url_for('static',filename='chart/bootstrap/bootstrap.min.js') }}"></script>
<script src="{{ url_for('static',filename='chart/plugins/layer/layer.js') }}"></script>

<script src="{{ url_for('static',filename='chart/common.js') }}"></script>
<script src="{{ url_for('static',filename='chart/plugins/highcharts/highcharts.js') }}"></script>
<script src="{{  url_for('static',filename='chart/chart.js') }}"></script>
<script src="{{  url_for('static',filename='chart/index/index.js') }}"></script>
<script>
    var dashboard_index_ops = {
        init: function () {
            this.drawChart();
        },
        drawChart: function () {
            charts_ops.setOption();
            $.ajax({
                url: common_ops.buildUrl("dashboard"),
                dataType: 'json',
                success: function (res) {
                    charts_ops.drawLine($('#member_order'), res.data)
                }
            });

            $.ajax({
                url: common_ops.buildUrl("finance"),
                dataType: 'json',
                success: function (res) {
                    charts_ops.drawLine($('#finance'), res.data)
                }
            });
        }
    };

    $(document).ready(function () {
        $("#g-1").addClass("active");
        $("#g-1-1").addClass("active");
        dashboard_index_ops.init();
    });
</script>


{% endblock %}

用的到毕设上,效果还不错
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43746433/article/details/105021597
今日推荐