Django中的模板
Django中的模板其实就是HTML文档,在文档中使用特殊的符号来对视图函数要传入的变量进行字符串格式化,最终生成一个静态页面。
模板文件的加载顺序:①去配置的模板目录下寻找(在settings.py中);
②去各个应用下的templates目录中寻找(无需配置,会自动查找)。
render函数的实现过程:①加载模板文件;
②定义模板上下文并给其传参;
③模板渲染产生标准的html内容,封装为render(request, ‘模板路径’, 参数字典);
模板语言(Django Template Language)
在html中书写并生效,用于接收和使用传入的数据。
模板变量:由数字、字母、下划线和点组成,但不能以下划线开头,其解析顺序以{{ book.title }}为例
①把book作为字典,取book[‘title’];
②把book作为一个对象,将title作为属性,book.title;
③把book作为一个对象,将title作为方法,取book.title;(其中book可以是字典/对象/列表等,如book.0则会先将book作为字典取book[‘0’],再将book作为列表取book[0])(注意当解析失败的时候不报错,会使用空字符串填充模板变量);
模板标签:用于在模板(html文件)中应用语句,其应用方法遵照python语言的方式,常用的有
①{% for %}{% forloop.counter %}(记录循环次数){% empty %}(无内容时显示){% endfor %};
②{% if/else/elif %}{% endif %}其中支持比较运算符和逻辑运算符;
③{% ifequal/ifnotequal value1 value2%}{% else %}(判断值1和2是否相等,不支持复杂数据类型如列表字典等);
④{# 单行注释 #}{% comment %}多行注释{% endcomment %}(模板的注释在html源代码中时看不到的);
模板过滤器:用于在显示变量之前变更值(其实现方式类似于lambda函数),以下为一些常用的模板过滤器:
①{{ value|add:‘2’ }}(注意不要随意添加空格)
②capfirst首字母大写
③cut:'xxx’从字符串中移除指定的字符
④default:'xx’当值为空时用以代替
⑤date格式化日期字符串,如date:‘Y年m月d日’
⑥first/last返回列表中的首/末值
⑦length求字符串或列表的长度
⑧upper/lower大/小写
⑨time:格式化时间
自定义模板过滤器:过滤器其实就是python函数,其使用流程如下
①在应用下新建目录templatetags,创建__init__.py,创建filters.py文件;
②在filters.py文件中from django.template import Library,并创建register = Library();
③创建过滤器函数,自定义的过滤器函数至少有一个参数,最多有两个参数;
④使用@register.filter装饰自定义过滤器函数;
⑤在模板文件(html)中使用,在标签上方添加{% load filters %},函数名即为自定义过滤器,其第一个参数即为要过滤的变量,如需第二个参数,则:'xx’添加。
自定义标签:定义方法与自定义过滤器类似,但使用@register.simple_tag装饰,使用时{% 函数名 参数1 参数2 %}即可返回值。
模板继承:①建立父模板,一般将所有页面都相同的内容建立在父模板中(也是一个html文件);
②继承父模板,在子文件中使用{% extends ‘url’ %}(相对于templates目录)来继承父模板的全部内容,输入重写块之外内容无效;
③在父模板中使用{% block blockname %}xxx{% endblock blockname %}建立块并对其命名,在子文件中可以使用相同的标签来对父模板的块内容重写(重写后丢失父模板内容),使用{% block.super %}可在重写后也将父模板原本在此块中的内容输入。
*注:若不重写,则父模板中的所有块中内容都会继承并显示(即若不需要继承此块内容则需重写为空),block可以嵌套,模板可以嵌套继承,即可以出现中间模板。
html转义:从视图函数传入模板的变量会默认使用html实体字符,即将一些可能冲突的符号转义,若要直接传入html文档,则必须对其中的符号禁止转义,有以下几种方式:
①使用过滤器,{{ content|safe }},可以禁止content中的字符转义
②使用标签{% autoescape off %}xxx{% endautoescape %},可以禁止此标签中的所有内容转义
③硬编码(即直接写在html文档中的字符串)中的字符串默认不转义(即识别为标签),若要转义(即识别为<>)则需手动使用html实体字符。
与模板相关的其他内容
CSRF(Cross Site Request Forgery)攻击
也称XSRF,跨站请求伪造,其原理为利用浏览器保持的登录状态伪造请求(通过第三方网站的跳转指令,携带浏览器的cookie,以浏览器的权限执行恶意提交的请求),其根本原因为浏览器的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的,一些常见的防御方法如下:
①对于敏感操作尽量使用POST;
②验证HTTP referer,HTTP请求头中有一个字段名为referer,其记录了该HTTP请求的来源地址,可被用于检查请求是否来自合法的“源”(Referer值是否是指定页面,或者网站的域),但referer值并能确保获取到,用户可设置其不可见;
③在请求地址中添加csrf token,其会向cookie中写入一条名为csrftoken值为随机生成的数据,服务器会对比该值对不符合要求的请求返回403,
Django中,在form标签下添加{% csrf_token %}标签,并默认打开csrf中间件,即开启了csrf防护。(注意若不添加该标签,则本地的提交也会被拦截)
XSS(Cross Site Scripting)攻击:其原理与SQL注入类似,通过提交的数据来更改原始代码结构,并在页面上运行脚本,对其进行预防常用方法如下:
①输入验证,使用标准输入验证机制,验证所有输入数据的长度、类型、语法及业务逻辑;
②输出编码,确保用户提交的数据已经被正确编码并不允许用户自主选择编码方式。
url反向解析:根据path匹配的正则表达式动态生成url,使得更改path时(即更改地址栏中输入的地址时)对应的视图函数和模板文件中的url无需改动,反向解析在Django中应用于模板中的超链接/视图中的重定向,其使用方法如下:
①在项目/项目名下的urls文件中定义path(‘url’, include((‘应用名.urls’, ‘应用名’) namespace=‘应用名(可变)’))(注意在Django2.x中存在namespace时需使用元组说明要指定的应用名),在应用下的urls文件中定义path(‘xx’, views.xx, name=‘xx’),在模板中使用标签{% url ‘namespace:appname’ %}即可反向解析至匹配的url;
②在模板中使用{% url ‘namespace:xxx’ 参数1 参数2 %}其后的参数匹配的是定义path中的url的分组(若分组不对应则报错),会将写在后面的参数分配进分组,生成url;
③在模板中使用{% url ‘namespace:xxx’ a=参数1 b=参数2 %}其后的参数匹配定义path中的url的命名分组,参数名需对应r'xxx/xx/(?P<a>\d)xx(?P<b>\d)',将关键字参数填入分组,生成url;
④在视图函数中使用反向解析,redirect(reverse(‘namespace:xx’, args=(位置参数元组), kwargs={‘a’:1关键字参数字典})),reverse函数专用于url的反向解析。
静态文件:若要在模板页面上使用静态文件,则需要严格区分静态文件与页面的请求:
①需要创建目录,并在setting中配置,STATIC_URL = '/static/'意为访问静态文件的url配置(HTML中需要的静态文件都会重新发起一个请求,Django强制要求静态文件(css/img等)必须使用static(否则禁止访问),然后再根据href/src请求的url去本地文件夹物理目录中查找),STATICFILES_DIRS配置静态文件的物理目录;
②从django.conf import settings中可以查看静态文件的查找顺序STATICFILES_FINDERS,先查找配置的目录下,再去应用下的文件夹中查找;
③可以在模板中动态的生成静态文件的url(类似于url的反向解析),主要是解决STATIC_URL变动的问题(即改变STATIC_URL时无需改变HTML文档中对静态文件的访问url),在最上方{% load staticfiles %},在需要配置url的地址中如src="{% static ‘images/mm.jpg’ %}";
关于IP拦截:使用request.META[‘REMOTE_ADDR’]可以获取浏览器端的IP地址,通过中间件类的设计可以在视图函数应用之前对浏览器的IP进行筛选,实现阻止某些IP访问网站的功能。
中间件:是Django预留的函数接口,可以介入Django的请求和响应处理过程,修改Django的输入或输出,中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性,其它的MVC框架也有这个功能,名称为IoC。
(1)在应用下创建middleware.py文件,在其中定义中间件类,一般命名方式为 class IPBlockMiddleware,类中的方法(最多有五个参数self, request, 视图函数, *args, **kwargs)即Django为中间件类预留的函数(函数名不可变),在setting.py中的MIDDLEWARE列表中注册,注册时写为python包名,即‘项目名.middleware.类名’,中间件中可重写的方法如下:
①__init__(self):服务器重启后,响应第一个请求的时候调用;(即后续请求不调用);
②process_request(self, request):是在产生request对象,进行url匹配之前调用;
③process_view(self, request, view_func, *view_args, **view_kwargs):是url匹配之后,调用视图函数之前;
④process_response(self, request, response):视图函数调用之后,内容返回给浏览器之前;(其中response为视图的返回值);
⑤process_exception(self, request, exception):视图函数出现异常,会调用这个函数。
(2)在setting中MIDDLEWARE列表中为中间件类的注册,如果有多个中间件类包含process_exception函数,则先注册的后执行;
(3)Django的中间件请求处理流程为:浏览器发出请求→产生request对象→调用中间件类中的process_request→url匹配→调用中间件类中的process_view→调用视图函数→调用中间件类中的process_response→返回给浏览器response对象;
(4)中间件函数分为两类:
①请求阶段中process_request/view,应返回None(继续执行其他中间件类中的process_request/view,按MIDDLEWARE中从上到下的顺序执行)或HttpResponse(不执行后续的视图/中间件,直接将此HttpResponse返回给响应中间件);
②响应阶段中process_template_response/response/exception,其中process_template_response在视图完成执行后立即执行,必须返回一个实现render方法的响应对象,process_response在所有响应返回浏览器之前执行,必须返回一个HttpResponse/StreamingHttpResponse对象,该方法必须调用(即使跳过了视图和中间件视图函数),process_exception在产生异常时执行,应返回一个None(启用默认的异常处理)/HttpResponse对象(所有的响应阶段中的中间件函数,按MIDDLEWARE中从下到上的顺序执行)。
Django中的分页显示
Django中自带了Paginator类用于实现与分页相关的功能,其在视图函数和模板中的使用方法如图所示,其属性和方法如下:
设置分页显示:分页显示,并下方添加页码跳转及上一页/下一页链接,在模板中使用列表,在视图函数中操作并返回页码及当前页需要的内容,from django.core.paginator import Paginator,在视图函数中首先查询获取查询集,生成Paginator对象p = Paginator(查询集, 10/每页条数)
Paginator类实例对象
方法_init_(列表,int):返回分页对象,第一个参数为列表数据,
第二个参数为每页数据的条数。
属性count:返回对象总数。
属性num_pages:返回页面总数。
属性page_range:返回页码列表,从1开始,例如[1, 2, 3, 4]。
方法page(m):返回Page类实例对象,表示第m页的数据,下标以1开始,是一个可迭代对象。
Page类实例对象
调用Paginator对象的page()方法返回Page对象,不需要手动构造。
属性object_list:返回当前页对象的查询集。
属性number:返回当前是第几页,从1开始。
属性paginator:当前页对应的Paginator对象。
方法has_next():如果有下一页返回True。
方法has_previous():如果有上一页返回True。
方法len():返回当前页面对象的个数。
方法previous_page_number():返回上一页的页码。
方法next_page_number():返回下一页的页码。