后端渲染
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则不能调用该方法(避免误操作的风险),模型对象动态生成的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.模板加载器(后面优化部分会提到)
- 文件系统加载器
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语言规范.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 / 统计报表
- 向浏览器传输二进制数据。
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):
# 创建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']
# 通过嵌套的循环将员工表的数据写入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只能减少内存的开销,但是如果下载一个大文件会导致一个请求长时间占用服务器资源,比较好的做法还是把报表提前生成好(可以考虑使用定时任务),放在静态资源服务器或者是云存储服务器上以访问静态资源的方式访问
- ECharts或Chart.js。
- 思路:后端只提供JSON格式的数据,前端JavaScript渲染生成图表。
def get_charts_data(request):
"""获取统计图表JSON数据"""
names = []
totals = []
# 通过connections获取指定数据库连接并创建游标对象
with connections['backend'].cursor() as cursor:
# 在使用ORM框架时可以使用对象管理器的aggregate()和annotate()方法实现分组和聚合函数查询
# 执行原生SQL查询(如果ORM框架不能满足业务或性能需求)
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})
统计图表