Django+Echarts画图实例
所有演示均基于Django2.0
閱讀此篇文章你可以:
- 了解Django中aggregate和annotate函數的使用方法
- 獲取一個Django+Echarts繪制柱狀圖的完整示例
需求說明
一張會議記錄表,里邊有一個字段存放會議舉行的地點,例如北京、上海、洛陽等等,需要取舉行會議最多的前20個地點繪制成柱狀圖展示,項目為前后端分離的架構
需求分析
看了需求主要有三個關鍵點:
1.前后端分離:前端只負責頁面渲染,后端提供API負責數據輸出
2.需要繪制成柱狀圖:繪制圖表的第三方插件有很多,我們這里就選擇百度開源的echarts,簡單好用且功能強大
3.取舉行會議最多的前20個地點:了解一點SQL知識的話就知道需要先要對地點字段進行group by,然后order by desc倒序,最后limit取前20
那么在Django中應該如何group by,并在group by之后order by排序,最后limit呢?這里我們介紹django的兩個函數aggregate和annotate
aggregate
aggregate聚合函數,用于對QuerySet整個對象結果的匯總,例如獲取員工總數(COUNT),平均(AVG)年齡,最大(MAX)年齡,最小(MIN)年齡,銷售總額(SUM)等,輸出的結果是一個字典
我們有一個model如下:
class Employee(models.Model):name = models.CharField(max_length=32, verbose_name='姓名')age = models.IntegerField(verbose_name='年齡')salary = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='薪資')想要獲取員工的工資總額,我們可以這樣寫
>>> from django.db.models import Sum>>> Employee.objects.aggregate(Sum('salary')) {'salary__sum': Decimal('5000.00')}想要同時獲取員工的平均年齡、最大年齡和最小年齡,我們可以這樣寫
>>> from django.db.models import Avg, Max, Min>>> Employee.objects.aggregate(Avg('age'), Max('age'), Min('age')) {'age__avg': 23.333333333333332, 'age__max': 30, 'age__min': 18}annotate
annotate函數區(qū)別于aggregate函數的一個最重要的地方是annotate函數輸出的結果是一個QuerySet對象,這個非常重要,aggregate函數最后輸出的結果是個字典,也就不能再在字典的基礎上進行QuerySet操作了,而annotate函數執(zhí)行完成后輸出QuerySet對象可以繼續(xù)調用Django內置的filter、order_by等函數來完成更加復雜的查詢計算操作
用到annotate函數的邏輯往往比較復雜,Django非常人性化的提供了query方法,方便查看annotate生成的SQL語句幫助我們確定執(zhí)行過程
以上邊的實際需求為例,model如下:
class EventInfo(models.Model):event_location = models.CharField(max_length=30)class Meta:db_table = "app_event_info"我們需要先對地點event_location進行group by:
>>> _t = EventInfo.objects.values_list('event_location').annotate(Count('id'))# values_list可以獲取evnet_location的元組列表。 # values_list方法加個參數flat=True可以獲取event_location的值列表。group by之后我們就需要order by排序了,如果我們不知道order by的字段,我們可以通過query先查看group by生成的SQL語句
>>> print(_t.query) SELECT "app_event_info"."event_location", COUNT("app_event_info"."id") AS "id__count" FROM "app_event_info" GROUP BY "app_event_info"."event_location"這個時候可以看到實際上輸出的結果有一個叫id__count的字段表示地點的總數,那么我們就可以接著對地點總數進行排序了,因為是要倒敘,需要在字段名id__count前邊加上-號來表示倒序
>>> _x = _t.order_by('-id__count') >>> >>> print(_x.query) SELECT "app_event_info"."event_location", COUNT("app_event_info"."id") AS "id__count" FROM "app_event_info" GROUP BY "app_event_info"."event_location" ORDER BY "id__count" DESC最后limit取前二十,Django中l(wèi)imit可以直接通過QuerySet結果后加python的數組切片語法來實現,就像[0:20](其中0可以省略)相當于limit 20一樣,[10:20]意思為取第10到第20條數據
>>> _y = _x[:20] >>> >>> print(_y.query) SELECT "app_event_info"."event_location", COUNT("app_event_info"."id") AS "id__count" FROM "app_event_info" GROUP BY "app_event_info"."event_location" ORDER BY "id__count" DESC LIMIT 20上邊的每一步我們都通過query打印了SQL,確定是我們想要的結果了。需求分析清楚,所有的關鍵點我們也都知道怎么處理了,那么接下來實現就水到渠成了。
實現代碼
URL如下:
from django.urls import path from django.views.generic.base import TemplateViewfrom .views import echarts_data urlpatterns = [path('echarts/', TemplateView.as_view(template_name='echarts.html'), name='echarts-url'),path('api/echarts/', echarts_data, name='api-echarts') ]因為是前后端分離的,所以我這里用了兩個urlecharts和api/echarts
echarts為前臺訪問地址,對應下邊的html代碼,通過ajax方式調用后端接口,所以這里直接用了TemplateView,不需要再寫額外的view代碼
api/echarts為后端API的地址,對應下邊的view代碼,為前臺提供數據接口
前端HTML:
<!DOCTYPE html> <html> <head><meta charset="utf-8"><title>ops-coffee</title><!-- 引入 echarts.js --><script src="/static/js/jquery.min.js"></script><script src="/static/js/echarts/echarts.common.min.js"></script> </head> <body><!-- 為ECharts準備一個具備大小(寬高)的Dom --><div id="main" style="height:400px;"></div><script type="text/javascript">// 基于準備好的dom,初始化echarts實例var myChart = echarts.init(document.getElementById('main'));$.ajax({type: "get",url: "/api/echarts",dataType: "json",success: function (data) {// 指定圖表的配置項和數據var option = {title: {left: 'center',text: 'ops-coffee 運維咖啡吧'},tooltip: {},xAxis: {data: data.key},yAxis: {},series: [{name: '數量',type: 'bar',data: data.value}]};// 使用剛指定的配置項和數據顯示圖表。myChart.setOption(option);},error: function () {alert('Error: ajax 請求出錯!')}});</script> </body> </html>實例比較簡單,抄的echarts官方示例,這里會看到echarts渲染圖形實際上只需要X軸和Y軸兩個數據變量,且都為list列表類型
后端VIEW:
from django.http import JsonResponse from django.db.models import Countfrom .models import EventInfodef echarts_data(request):_x = EventInfo.objects.values_list('event_location').annotate(Count('id')).order_by('-id__count')[:20]jsondata = {"key": [i[0] for i in _x],"value": [i[1] for i in _x]}return JsonResponse(jsondata)最核心的那行group by + order by + limit的ORM拼接,我們上邊已經詳細的介紹過了,那么這里只需要在輸出的結果中單獨的把城市跟數量轉成兩個列表對應echarts里邊需要的X軸Y軸數據就可以了
最后訪問url:https://ops-coffee.cn/echarts 可以看到我們想要的結果
整個Demo示例介紹完成。
如果你覺得文章對你有幫助,請轉發(fā)分享給更多的人。如果你覺得讀的不盡興,推薦閱讀以下文章:
- Django model轉字典的幾種方法
- Django model select的各種用法詳解
轉載于:https://www.cnblogs.com/37Y37/p/10018397.html
總結
以上是生活随笔為你收集整理的Django+Echarts画图实例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python简单使用
- 下一篇: 编译出现的问题解决