xss攻击
XSS攻击全称跨站脚本攻击,是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS,XSS是一种在web应用中的计算机安全漏洞,
它允许恶意web用户将代码植入到提供给其它用户使用的页面中。
为了防止xss攻击djano是这样做的?
auto_escape (自动转义):何谓转义?就是把html语言的关键字过滤掉。例如,<div>就是html的关键字,如果要在html页面上呈现<div>,其源代码就必须是<div>
Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。
但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。
为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。
比如:后端传过来的是:
value = "<a href='#'>点我</a>"
我们可以在前端页面上这样设置:
{{ value|safe}}
常用语法
只需要记两种特殊符号:
{{ }}和 {% %}
变量相关的用{{}},逻辑相关的用{%%}。
变量
{{ 变量名 }}
变量名由字母数字和下划线组成。
点(.)在模板语言中有特殊的含义,用来获取对象的相应属性值。
几个例子:
view中代码:
def template_test(request):
l = [11, 22, 33]
d = {"name": "alex"}
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def dream(self):
return "{} is dream...".format(self.name)
Alex = Person(name="Alex", age=34)
Egon = Person(name="Egon", age=9000)
Eva_J = Person(name="Eva_J", age=18)
person_list = [Alex, Egon, Eva_J]
return render(request, "template_test.html", {"l": l, "d": d, "person_list": person_list})
模板中支持的写法:
{# 取l中的第一个参数 #}
{{ l.0 }}
{# 取字典中key的值 #}
{{ d.name }}
{# 取对象的name属性 #}
{{ person_list.0.name }}
{# .操作只能调用不带参数的方法 #}
{{ person_list.0.dream }}
Filters
语法: {{ value|filter_name:参数 }}
default
{{ value:default: "nothing"}}
如果value值没传的话就显示nothing
length
{{ value|length }}
'|'左右没有空格没有空格没有空格
返回value的长度,如 value=['a', 'b', 'c', 'd']的话,就显示4.
filesizeformat
将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。例如:
{{ value|filesizeformat }}
如果 value 是 123456789,输出将会是 117.7 MB。
slice
切片
{{value|slice:"2:-1"}}
date
格式化'
html 代码:
{{ value|date:"Y-m-d H:i:s"}}
views.py 代码
import datetime
now=datetime.datetime.now()
truncatechars
如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。
参数:截断的字符数
{{ value|truncatechars:9}}
自定义filter
自定义filter代码文件摆放位置:
app01/
__init__.py
models.py
templatetags/ #注意这个文件名字一定要一样不可改变,这个是一个python包
__init__.py
app01_extras.py
views.py
编写自定义filter
from django import template #先导入
register = template.Library() # 再注册,注意Library后面有括号
@register.filter(name="cut") #name 只是个别名
def cut(value, arg):
return value.replace(arg, "")
@register.filter(name="addSB")
def add_sb(value):
return "{} SB".format(value)
使用自定义filter
{ somevariable|cut:"0" }}
{{ {{ d.name|addSB }} }}
在前面页面的代码:
{% load app_01tap %} {#先在HTML中导入你写的那个函数#}
{{ s1|s8:"我们" }} #s1是我们要输入的内容 s8是我们定义的函数名,'我们'是函数中要传入的参数arg
模板标签
标签看起来像是这样的: {% tag %}。标签比变量更加复杂:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。
一些标签需要开始和结束标签 (例如{% tag %} ...标签 内容 ... {% endtag %})。
for
<ul>
{% for user in user_list %}
<li>{{ user.name }}</li>
{% endfor %}
</ul>
for循环可用的一些参数:
| Variable | Description |
|---|---|
forloop.counter |
当前循环的索引值(从1开始) |
forloop.counter0 |
当前循环的索引值(从0开始) |
forloop.revcounter |
当前循环的倒序索引值(从1开始) |
forloop.revcounter0 |
当前循环的倒序索引值(从0开始) |
forloop.first |
当前循环是不是第一次循环(布尔值) |
forloop.last |
当前循环是不是最后一次循环(布尔值) |
forloop.parentloop |
本层循环的外层循环 |
for ... empty
<ul>
{% for user in user_list %}
<li>{{ user.name }}</li>
{% empty %}
<li>空空如也</li>
{% endfor %}
</ul>
if,elif和else
{% if user_list %}
用户人数:{{ user_list|length }}
{% elif black_list %}
黑名单数:{{ black_list|length }}
{% else %}
没有用户
{% endif %}
当然也可以只有if和else
{% if user_list|length > 5 %}
七座豪华SUV
{% else %}
黄包车
{% endif %}
if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。
with
定义一个中间变量
{% with total=business.employees.count %}
{{ total }} employee{{ total|pluralize }}
{% endwith %}
csrf_token
这个标签用于跨站请求伪造保护。
在页面的form表单里面写上{% csrf_token %}

注释
{# ... #}
母板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
{% block page-css %} #替换css的快
{% endblock %}
</head>
<body>
<h1>这是母板的标题</h1>
{% block page-main(自己起的块的名字) %}
这是需要替换的地方
{% endblock %}
</body>
</html>
注意:我们通常会在母板中定义页面专用的CSS块和JS块,方便子页面替换。
继承母板
子页面要用模板是,首先在子页面中在页面最上方使用下面的语法来继承母板。
{% extends 'layouts.html' %}
块(block)
通过在母板中使用{% block xxx %}来定义"块"。
然后在子页面中通过定义母板中的block,然后在块内写入子页面的内容。注意block块的名字要和母版中的块的名字相同,
{% block page-main %}
<p>世情薄</p>
<p>人情恶</p>
<p>雨送黄昏花易落</p>
{% endblock %}
组件
可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方按如下语法导入即可。弊端: 谁用这个组件谁的后端还需要传参数
{% include 'navbar.html' %}
静态文件相关
{% load static %}
<img src="{% static "images/hi.jpg" %}" alt="Hi!" />
引用JS文件时使用:
{% load static %}
<script src="{% static "mytest.js" %}"></script>
某个文件多处被用到可以存为一个变量
{% load static %}
{% static "images/hi.jpg" as myphoto %}
<img src="{{ myphoto }}"></img>
使用get_static_prefix
{% load static %}
<img src="{% get_static_prefix %}images/hi.jpg" alt="Hi!" />
或者
{% load static %}
{% get_static_prefix as STATIC_PREFIX %}
<img src="{{ STATIC_PREFIX }}images/hi.jpg" alt="Hi!" />
<img src="{{ STATIC_PREFIX }}images/hi2.jpg" alt="Hello!" />
自定义simpletag
和自定义filter类似,只不过接收更灵活的参数。
定义注册simple tag
@register.simple_tag(name="plus")
def plus(a, b, c):
return "{} + {} + {}".format(a, b, c)
使用自定义simple tag
{% load app01_demo %}
{# simple tag #}
{% plus "1" "2" "abc" %}
创建自定义模板标签
背景原因
Django有许多内置的模板标签(template tags)比如{% if %} ,{% for cate in cate_list %}.... 如果这些模板标签不能满足您的需要,你也可以自己定义模板标签.
Django提供了以下帮助函数(functions)来允许你以一种简单的方式创建自己的模板标签(template tags):
- simple_tag:处理数据并返回一个字符串(string) , 从前端取数据,然后在后端处理成变量,替换前端. 例子:计算器
- inclusion_tag:处理数据并返回一个渲染过的模板(template),后端处理数据渲染前端页面
- assignment_tag:处理数据并在上下文(context)中设置一个变量(variable),这个我还没遇到过:
模板中自定义函数
- 在已注册的app中创建一个名字叫 templatetags 的包,这个文件夹的名字必须叫它. 这个app,一定在setting.py 中的installapps中已经注册,也就是存在
- 在其下任意创建一个py文件, 比如叫text1.py文件的命名是非常重要的。你将在模板(template)中使用这些模块的名字加载你的标签(tags)。
- 创实例化一个名字叫register 的Library类的对象
- 定义函数
- 在使用自定义simple_tag和filter的html文件中导入之前在templatetags中创建的py文件
#第一种方法: register.filter 过滤器
HTML中的参数传入到函数中当做该函数的参数,然后该函数返回数据给前端渲染页面.
第一个例子:
from django import template register = template.Library() @register.filter def f(a): print(a) return "你好"
html页面:设置为:
{% load text1 %} #先导入这个文件
{{ "建超"| f }}
后端打印结果为:
建超
前端页面渲染为:
你好
第二个例子: 在前端页面中f2可以先传入个参数,最后会一起传到后端来.,注意后端的f2()中也要有两个参数
from django.template import Library register=Library() @register.filter #必须要加上装饰器 def f2(a1,a2): #这种方法这里只能传两个参数,但是可以放在if判断中 data= "我的名字叫%s,我喜欢%s"%(a1,a2) return data
HTML:
{% load text1 %} #先导入这个文件
{{ "建超"|f2:"小红" }} 第二个参数是函数后边紧跟着冒号然后跟参数
页面:

#第二种方法 @ register.simple_tag #这个可以传传多个参数装饰器和上面的不一样了, 但是这种方法不能放在if判断中
@register.simple_tag #这个是传多个参数装饰器和上面的不一样了, 但是这种方法不能放在if判断中 def f3(a1,a2,a3,a4): data=a1+a2+a3+a4 return data
HTML
{% load text1 %} #先导入这个文件
{% f3 4 45 46 47 %} #这里的调用方式和
前端:

register.filter 用在if 判断 中
@register.filter def f4(a1): if "alex" in a1: return "哈哈哈" #我发现,其实你在这里返回什么都无所谓 else: return False
html
{% if "adljallex"|f4 %}
<p>"回答正确"</p>
{% else %}
<p>"回答错误"</p>
{% endif %}
页面:

第三个例子:blog博客系统左侧页面
- inclusion_tag("需要渲染的html文件"):处理数据并返回一个渲染过的模板(template),后端处理数据渲染前端页面. 这个函数主要用在给母版传递数据
templatetags 下的my_tag.py文件
from django import template
register=template.Library()
@register.inclusion_tag("base_tag.html") #括号里的HTML文件并不是母版中的HTML,而是需要传递数据的HTML页面
def get_archive_style(request):
menus_list = request.session["menus_list"]
menu_dict = {}
for i in menus_list:
if not i["parent_id"]:
i["active"] = False
menu_dict[i["permissions_id"]] = i
# 处理menus_list中的active值
import re
current_path = request.path_info
for i in menus_list:
url = "^%s$" % (i["url"])
if re.match(url, current_path):
if i["parent_id"]:
menu_dict["permissions_id"]["active"] = True
else:
i["active"] = True
menu_dict1 = {} #最后要的总值
for i in menu_dict.values():
if i["menus_id"] in menu_dict1.keys():
temp = {"title": i["permissions__title"], "url": i["url"], "active": i["active"]}
menu_dict1[i["menus_id"]]["children"].append(temp)
if i["active"]:
menu_dict1[i["menus_id"]]["active"] = True
else:
menu_dict1[i["menus_id"]] = {
"menu_name": i["menus__caption"],
"active": i["active"],
"children": [
{
"title": i["permissions__title"],
"url": i["url"],
"active": i["active"]
}
]
}
return {"menu_dict1":menu_dict1}
base_tag.html. 母版中的哪部分html代码需要传数据,把这部分代码剪切出来单独写一个html文件叫base_tag.html
{% for item in menu_dict1.values %}
<p class="menu1"><a href="/m1/">{{ item.menu_name }}</a></p>
{% if item.active %}
<div class="list">
{% else %}
<div class="list hide">
{% endif %}
{% for son in item.children %}
{% if son.active %}
<p><a href="{{ son.url }}" class="active">{{ son.title }}</a></p>
{% else %}
<p><a href="{{ son.url }}" class=" ">{{ son.title }}</a></p>
{% endif %}
{% endfor %}
</div>
{% endfor %}
</div>
base.html
{% load base_tag %} //导入templatetags文件夹中的py文件 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <!--IE浏览器最高渲染--> <meta name="viewport" content="width=device-width, initial-scale=1"> <!--为了确保适当的绘制和缩放--> <title>Title</title> {# <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">#} <style> * { margin: 0; } .header { width: 100%; height: 80px; background-color: coral; } .menu { width: 200px; height: 660px; background-color: darkgrey; color: white; float: left; } .hide { display: none; } .list { margin-left: 20px; margin-top: 10px; } .active { color: green; } a { text-decoration: none; } </style> </head> <body> <div class="header"> <h3>管理页面</h3> </div> <div class="content"> <div class="row"> <div class="menu col-md-3"> {% get_archive_style request %} //导入py文件中的方法,并且传参数 </div> <div class="col-md-8"> {% block content_right %} {% endblock %} </div> </div> </body> </html>

浙公网安备 33010602011771号