django:数据收集与统计可视化的简单设计
在あつまれ どうぶつの森中,每周日的上午(12:00前)可以购买大头菜,而周一到周六可在卖出大头菜。大头菜的价值是会浮动的,每天闭店时和中午12:00分别更新一次,也就是每周有12次的价格变动,如果在一周之内没有把菜卖掉,那么周日这些菜就会变成烂菜,不能再卖。
大头菜实际上就是芜菁,日语中叫作 カブ ,与日语中的股份一词“株” 同音,这个游戏机制确实有点像只有1支股的股票交易。
switch肯定没有API,数据只能手动输入。现在要设计一个统计系统,就是将历来的大头菜数据都收集起来,每周日进行归档。
由于服务运行在本地,就没有连接数据库,数据都存储在文件当中。处理逻辑是这样的:主页显示了本周和上周的购入价格和卖出价格曲线。如果检查到当前时段的价格还没有填入,表单就处于显示状态,可以填写当前的价格,填写后保存数据并跳转回主页。
效果展示:
django是MVC开发模式,初始化一个django项目之后,urls.py当中定义的是各种url访问入口,views.py定义的是各种处理函数代表控制器(C),Models.py当中定义的是数据模型(M),一般在template文件夹下的各个模板文件代表视图(V).
创建一个项目,起名为Brassica(大头菜),并在 Brassica/下建立文件夹template和data,template存放HTML模板,data存放数据。项目Brassica/下打开settings.py,将其中的TEMPLATES=[‘DIRS’:[]…]改为
TEMPLATES=[... 'DIRS': [BASE_DIR+"/Brassica/templates/"], ...]
这样程序可以在这个路径下找到我们的模板文件。
在urls.py中,修改为如下形式,这样就可以执行跳转。
from django.conf.urls import url from . import index,fillData urlpatterns = [ url(r'^fillNewData',fillData.saveData), url(r'', index.home), ]
接下来就设计index.py中的home()函数和fillData.py中的saveData函数。
新建一个index.py用于控制主页的显示
from django.shortcuts import render import os import datetime def saveThisPeriodData(request,price): pass def isNeedToInputData(theData,fName): fp = open(fName) msg = fp.read().split("\n") if (theData.weekday()==6): if msg[0]=="0": return True else: idx = 2*theData.weekday() if(theData.hour>=12): idx+=1 r = eval(msg[1]) if(len(r)==0): return True elif idx != r[-1][0]: return True return False def home(request): nowData = datetime.datetime.now() def getThisSunday(now): if(nowData.weekday()==6): return nowData else: return nowData-datetime.timedelta(days=1+nowData.weekday()) def getLastSunday(thisSunday): return thisSunday-datetime.timedelta(days=7) thisSunday = getThisSunday(nowData) lastSunday = getLastSunday(thisSunday) fName = "Brassica/data/"+"{:04d}{:02d}{:02d}".format(thisSunday.year,thisSunday.month,thisSunday.day) if not (os.path.exists(fName)): with open(fName,"w") as fp: fp.write("0\n[]\n") fp=open(fName) msg = fp.read().split("\n") ctx = {} if not isNeedToInputData(nowData,fName): ctx["inputFrame"]="none" ctx["BoughtPrice"]=msg[0] ctx["priceList"]=msg[1] fp.close() ctx["currTime"] = nowData weekdayToChar = "一二三四五六日" ctx["weekDay"] = weekdayToChar[datetime.datetime.now().weekday()] fName = "Brassica/data/"+"{:04d}{:02d}{:02d}".format(lastSunday.year,lastSunday.month,lastSunday.day) fp=open(fName) msg =fp.read().split("\n") ctx["lastSundayBoughtPrice"] = msg[0] ctx["lastWeekPriceList"] = msg[1] fp.close() return render(request,"index",ctx)
以及用于存储数据的post响应
from django.shortcuts import render from django.views.decorators import csrf import datetime def saveData(request): nowData = datetime.datetime.now() if request.method=="POST" and request.POST: def getThisSunday(theData): if(theData.weekday()==6): return theData else: return theData-datetime.timedelta(days=1+theData.weekday()) thisSunday = getThisSunday(nowData) fName = "Brassica/data/"+"{:04d}{:02d}{:02d}".format(thisSunday.year,thisSunday.month,thisSunday.day) fp = open(fName,"r") msg = fp.read().split("\n") fp.close() print(msg) fp=open(fName,"w") if(nowData.weekday()==6): fp.write(request.POST['price']+"\n[]") else: idx = 2*nowData.weekday() if(nowData.hour>=12): idx+=1 r = eval(msg[1]) r.append( [idx,int(request.POST["price"])] ) fp.write(msg[0]+"\n"+str(r)) fp.close() return render(request,"post")
主页对应的模板:
<html> <head> <meta charset="UTF-8" /> <title>菜价</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://code.highcharts.com.cn/highcharts/highcharts.js"></script> <script src="https://code.highcharts.com.cn/highcharts/highcharts-more.js"></script> <script src="https://code.highcharts.com.cn/highcharts/modules/exporting.js"></script> <script src="https://img.hcharts.cn/highcharts-plugins/highcharts-zh_CN.js"></script> <script src="https://code.highcharts.com.cn/highcharts/themes/grid-light.js"></script> </head> <body> <div> {{currTime}}<br> 星期{{weekDay}} <br> <form style="display:{{inputFrame}}" action="/fillNewData" method="post"> {% csrf_token %} <p>当前菜价 <input type="text" name="price"/> </p> <input type="submit" value="Submit"> </form> </div> <div id="container" style="width: 1200px; height: 600px; margin: 0 auto"></div> <script language="JavaScript"> var chart = Highcharts.chart('container', { chart: { type:'spline', plotBorderWidth: 1, zoomType: 'xy' }, legend: { enabled: false }, title: { text: '大头菜价格统计' }, legend: { layout: 'vertical', align: 'right', verticalAlign: 'middle' }, xAxis: { gridLineWidth: 1, title: { text: '时间' }, categories: ['Mon A.M.', 'Mon P.M.', 'Tue A.M.', 'Tue P.M.', 'Wed A.M.', 'Wed P.M.', 'Thu A.M', 'Thu P.M.', 'Fri A.M.', 'Fri P.M', 'Sat A.M.', 'Sat P.M.'] }, yAxis: { startOnTick: false, endOnTick: false, title: { text: '菜价' }, maxPadding: 0.2, plotLines: [{ color: 'red', dashStyle: 'ShortDash', width: 2, value: {{BoughtPrice}}, label: { align: 'right', text:'周日购入价格:{{BoughtPrice}}', x: -10 }, zIndex: 3 }, { color: 'black', dashStyle: 'dot', width: 2, value: {{BoughtPrice}}, label: { align: 'left', text:'上周日购入价格:{{lastSundayBoughtPrice}}', x: 10 }, zIndex: 3 } ] }, plotOptions: { series: { dataLabels: { enabled: true, format: '{point.name}' } } }, series: [{ name:"本周", data: {{priceList}} }, { name:"上周", data: {{lastWeekPriceList}} }] }); </script> </body> </html>
POST请求对应的模板只需要1句话,跳转回主页即可
<script >window.location.href="/"</script >
这样,回到上一级目录,运行
python manage.py runserver 8809
就可以在端口8809运行程序