后端渲染
1.模板的配置和渲染函數
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates'), ],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
resp = render(request, 'index.html', {'foo': ...})
2.模板遇到變量名的查找順序琴拧。
- 字典查找(如:
foo['bar']
) - 屬性查找(如:
foo.bar
) - 方法調用(如:
foo.bar()
)- 方法不能有必須傳值的參數
- 在模板中不能夠給方法傳參
- 如果方法的
alters_data
被設置為True則不能調用該方法(避免誤操作的風險),模型對象動態(tài)生成的delete()
和save()
方法都設定了alters_data = True
.
- 列表索引查找(如:
foo[0]
)
3.模板標簽的使用贞谓。
{% if %} / {% else %} / {% endif %}
{% for %} / {% endfor %}
{% ifequal %} / {% endifequal %} / {% ifnotequal %} / {% endifnotequal %}
{# comment #} / {% comment %} / {% endcomment %}
4.過濾器的使用唧龄。
lower/upper/first/last/truncatewords/date/time/length/pluralize/center/ljust/rjust/cut/urlencode/default_if_none/filesizeformat/join/slice/slugify
5.模板的包含和繼承。
{% include %} / {% block %}
{% extends %}
6.模板加載器(后面優(yōu)化部分會提到)
- 文件系統(tǒng)加載器
TEMPLATES = [{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
}]
- 應用目錄加載器
TEMPLATES = [{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'APP_DIRS': True,
}]
前端渲染
1.前端模板引擎:Handlebars/Mustache
2.前端MV*框架。
- MVC - AngularJS
- MVVM(Model - View - ViewModel) - Vue.js
其他視圖
1.MIME(多用途Internet郵件擴展)類型 - 告知瀏覽器傳輸的數據類型玻蝌。
![1NBG$$A{38P[WJ)473M83.png](https://upload-images.jianshu.io/upload_images/14356833-a25c06ae114f2036.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2.如何處置生成的內容(inline / attachment)。
>>> from urllib.parse import quote
>>>
>>> response['content-type'] = 'application/pdf'
>>> filename = quote('Python語言規(guī)范.pdf')
>>> filename
'Python%E8%AF%AD%E8%A8%80%E8%A7%84%E8%8C%83.pdf'
>>> response['content-disposition'] = f'attachment; filename="{filename}"'
提醒:URL以及請求和響應頭中的中文都應該處理成百分號編碼
3.生成CSV / Excel / 統(tǒng)計報表
- 向瀏覽器傳輸二進制數據词疼。
buffer = ByteIO()
resp = HttpResponse(content_type='...')
resp['Content_Disposition'] = 'attachement;filename='...''
resp.write(buffer.,getvalue())
def get_style(name,color=0,bold=False,italic=False):
style = xlwt.XFStyle()
font = xlwt.Font()
font.name = name
font.colour_index = color
font.bold = bold
font.italic = italic
style.font = font
return style
def export_emp_excel(request):
# 創(chuàng)建Excel工作簿(使用三方庫xlwt)
workbook = xlwt.Workbook()
# 想工作簿中添加工作表
sheet = workbook.add_sheet('員工詳細信息')
# 設置表頭
titles = ['編號','姓名','主管','職位','工資','部門名稱']
for col, title in enumerate(titles):
sheet.write(0, col, title, get_style('HanziPenSC-W3', 2, True))
# 使用Django的ORM框架查詢員工數據
emps = Emp.objecets.all().select_related('dept').select_related('mgr')
cols = ['no', 'name', 'mgr', 'job', 'sal', 'dept']
# 通過嵌套的循環(huán)將員工表的數據寫入Excel工作表的單元格中
for row, emp in enumerate(emps):
for col, prop in enumerate(cols):
val = getattr(emp, prop, '')
if isinstace(val, (Dept, Emp)):
val = val.name
sheet.write(row + 1, col, val)
# 將Excel文件的二進制數據寫入內存
buffer = BytesIO()
workbool.save(buffer)
# 通過HttpResponse對象向瀏覽器輸出Excel文件
resp = HttpResponse(buffer.getvalue())
resp['content-type'] = 'application/msexcel'
# 如果文件名中有中文需要處理成百分號編碼
resp['content-disposition'] = 'attachment; filename = "detail.xls"'
return resp
- 大文件的流式處理:
StreamingHttpResponse
俯树。
def download_file(request):
file_stream = open('...', 'rb')
# 如果文件的二進制數據較大則最好用迭代器進行處理避免過多的占用服務器內存
file_iter = iter(lambda: file_stream.read(4096), b'')
resp = StreamingHttpResponse(file_iter)
#中文文件名要處理成百分號編碼
filename = quote('...', 'uft-8')
resp['Content-Type'] = '...'
resp['Content-Disposition'] = f'attachment;
filename = "{filename}"'
return resp
說明:如果需要生成PDF文件,可以阿娜黃reportlab贰盗。另外许饿,使用StreamingHttpResponse只能減少內存的開銷,但是如果下載一個大文件會導致一個請求長時間占用服務器資源舵盈,比較好的做法還是把報表提前生成好(可以考慮使用定時任務)陋率,放在靜態(tài)資源服務器或者是云存儲服務器上以訪問靜態(tài)資源的方式訪問
def get_charts_data(request):
"""獲取統(tǒng)計圖表JSON數據"""
names = []
totals = []
# 通過connections獲取指定數據庫連接并創(chuàng)建游標對象
with connections['backend'].cursor() as cursor:
# 在使用ORM框架時可以使用對象管理器的aggregate()和annotate()方法實現分組和聚合函數查詢
# 執(zhí)行原生SQL查詢(如果ORM框架不能滿足業(yè)務或性能需求)
cursor.execute('select dname, total from vw_dept_emp')
for row in cursor.fetchall():
names.append(row[0])
totals.append(row[1])
return JsonResponse({'names': names, 'totals': totals})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>統(tǒng)計圖表</title>
<style>
#main {
width: 600px;
height: 400px;
}
</style>
</head>
<body>
<div id="main"></div>
<script src="https://cdn.bootcss.com/echarts/4.2.0-rc.2/echarts.min.js"></script>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
var myChart = echarts.init($('#main')[0]);
$.ajax({
'url': 'charts_data',
'type': 'get',
'data': {},
'dataType': 'json',
'success': function(json) {
var option = {
title: {
text: '員工分布統(tǒng)計圖'
},
tooltip: {},
legend: {
data:['人數']
},
xAxis: {
data: json.names
},
yAxis: {},
series: [{
name: '人數',
type: 'bar',
data: json.totals
}]
};
myChart.setOption(option);
},
'error': function() {}
});
</script>
</body>
</html>