Django模版层
一 模板语法传值
{{}}:变量相关
{%%}:逻辑相关
#从视图函数的返回值中可以传入任意类型的变量到trmplate的html的文件中
#可以传入函数与类
1. 传入的函数会自动加括号调用
2. 在html文件中不能传入参数,不然不会被识别
3. 在浏览器中显示的是函数的返回值
4. 展示到html页面中也会触发类的__str__方法类似于打印
5. 传入类返回到html页面中的是类中的对象,也是相当于直接加括号调用实例化一个对象
6. 取列表或是字典中的单个元素只能用.的方式调用出来
# .索引 也可以 .键 也能两者混用
locals() 返回视图函数中所有定义的变量到html文件中
# 每一个web框架,都应该支持渲染模板
# 从视图函数的返回值中传入任意类型的变量到trmplate的html的文件中,然后再html文件中进行模板渲染的过程叫做DTL
过滤器
# 过滤器就类似于是模板语法内置的内置方法
# djangon内置有60多个过滤器,基本了解10个左右
# 基本语法
{{数据|过滤器:参数}}
变量名为 name
统计长度:{{ name |lenth }}
默认值:{{ name |default:'默认值' }} # name有值则打印这个值,没有比如false返回默认值
file_size=123321
文件大小: { { file_size | filesiezformat }} # 返回文件大小自动补单位
日期格式化:{{current_time|date:'Y-m-d H:i:s'}}
切片操作: {{ name|slice:'2:4'}} 从索引2开始切到索引4
切取字符: { info |truncatechars:6} 包含三个点 #你好啊...
切取单词: { info |truncatewords:9} 不包含三个(按照空格切,中文英文都是一样)
移除特定字符:{{ info | cut:''}} 清除字符串中的空格
拼接操作:{{list | join:'!'}} 列表拼接成字符串
拼接操作:{{number | add:10}} 如果是数字,做数学运算 。如果是字符串做拼接。如果都不是或一个数字一个 字符串返回空
#重要
前端:
hhh='<h1>阿里</h1>'
取消转义:{ { hhh }} 标签不可被识别
可以转义:{{hhh|safe}} 标签可被识别
后端:
res = mark_safe('<h1>阿里</h1>') 转义
'''
说明以后全栈项目时,前端代码不一定非要在前端页面书写
也可以先在后端写好,然后传递给前端页面
如果没有mark_safe保护则容易遭受xss攻击
简单介绍 就是输入的字符串可以转义成相关代码运行
那么在前端页面的input栏中如果输入恶意代码
后端拿到后是会保存到数据库中,且会被以代码的方式运行
那么就会造成数据不安全的隐患
但是django内置的mark_safe就解决了这个问题
'''
标签
# for 循环
{% for li in lis %}
<p>{{ forloop }}</p>
<p>{{ li }}</p>
{% endfor %}
# 打印了每次循环时当时变量的内置属性
-1.counter0:从0开始,每循环一次加1
-2.counter: 从1开始,每循环一次加1
-3.revcounter:从整体的长度开始,每循环一次减1一直到1(倒数)
-4.revcounter0:从最大的索引开始,每循环一次减1一直到0
-5.first:判断是不是循环的第一个
-6.last: 判断是不是循环的最后一个
-7.parentloop:父级forloop对象(for循环嵌套)
{'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 6, 'revcounter0': 5, 'first': True, 'last': False}
{'parentloop': {}, 'counter0': 1, 'counter': 2, 'revcounter': 5, 'revcounter0': 4, 'first': False, 'last': False}
{'parentloop': {}, 'counter0': 2, 'counter': 3, 'revcounter': 4, 'revcounter0': 3, 'first': False, 'last': False}
{'parentloop': {}, 'counter0': 3, 'counter': 4, 'revcounter': 3, 'revcounter0': 2, 'first': False, 'last': False}
{'parentloop': {}, 'counter0': 4, 'counter': 5, 'revcounter': 2, 'revcounter0': 1, 'first': False, 'last': False}
{'parentloop': {}, 'counter0': 5, 'counter': 6, 'revcounter': 1, 'revcounter0': 0, 'first': False, 'last': True}
# if 判断
{% if flag %}
<script>
alert('重新输入')
</script>
{% else %}
<script>
alert('登录成功')
</script>
{% endif %}
# 两者混用
{% for li in lis %}
{% if forloop.first %}
<p>这是我第一次</p>
{% elif forloop.last %}
<p>这是我最后一次</p>
{% else %}
<p>{{ li }}</p>
{% endif %}
{% empty %}
<p> for循环的迭代对象为空 </p> #不代表循环对象迭代完就能触发
{% endfor %}
# 起别名
{% with dic.hobby.3 as name %}
<p>{{name}}</p>
{% enwith %}
# csrf标签(了解)
自定义标签和过滤器
# 自定义标签
-1.在setting中的INSTALLED_APPS配置当前app,不然Django无法找到自定义的simple_tag
-2.在app中创建templatetags包 # 注意:包名只能是templatetags,不能改
-3.在包内,新建py文件 # 如:my_tags.py
-4.写过滤器的逻辑代码
from django import template
register = template.Library()
@register.filter
def my_upper(values):
return values.upper()
-5.渲染模板,先load,再使用
<p>内置的过滤器:{{ 'abab'|upper }}</p>
{% load my_tag %}
<p>自定义的过滤器:{{ 'abab'|my_upper }}</p>
# 自定义标签
-1.在setting中的INSTALLED_APPS配置当前app,不然Django无法找到自定义的simple_tag
-2.在app中创建templatetags包 # 注意:包名只能是templatetags,不能改
-3.在包内,新建py文件 # 如:my_tags.py
-4.写过滤器的逻辑代码
from django import template
from django.utils.html import mark_safe
register = template.Library()
@register.simple_tag
def my_csrf():
import uuid
res = uuid.uuid4()
return mark_safe('<input type="hidden" name="csrfmiddlewaretoken" value="%s">' % res)
-5.渲染模板,先load,在使用
{% csrf_token %}
{% my_csrf %}
'''
内置标签在浏览器显示:<input type="hidden" name="csrfmiddlewaretoken" value="ZefILcDWtxMlSb2mhS8bGbtscpnYRiJuctBGWRwGC7DMC0rZ3xLFwBznexljvKFI">
自定义标签在浏览器显示:<input type="hidden" name="csrfmiddlewaretoken" value="d39fd1ad-ba68-4123-af4b-82f5969bba1d">
'''
二 模板的继承
'''
有些网站的页面整体大差不差 风格形式相同 只是某一些局部在变化
'''
# 模板的继承 你自己先选好一个你想要继承的模板页面
{% entends 'home.html' %}
# 继承了之后页面跟模板页面长得一模一样,需要在模板页面上划定可以被修改的区域
{% block content %}
模板内容
{% endblock %}
# 子页面就可以声明想要修改的划定了的区域
{% block content %}
子页面内容
{% endblock %}
# 一般情况下模板页面上应该至少有三块可以被修改的区域
1.css区域
2.html区域
3.js区域
# 作用:每个子页面都可以有自己独有的css代码、html代码、js代码
'''
一般情况下 模板的页面划定的区域越多 扩展性越高
但是如果太多 不如自己写
'''
三 模板的导入
'''
将页面的某一个局部当成模块的形式
哪个地方需要就可以直接导入即可
'''
-第一步:新建一个 xx.html,把好看的模板写入
<div class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title">重金求子</h3>
</div>
<div class="panel-body">
详情点击:<a href="http://www.baidu.com">疯狂点我</a>
</div>
</div>
-第二步:在你想用的地方
{% include 'xx.html' %}
四 前后端交互编码方式
1.urlencoded----->传普通的数据,form表单默认就是这种----->request.POST
2.form-data------>传文件和数据 ----->request.POST request.FILES
3.json----------->传json格式数据 ------>request.body 反序列化处理
def index(request):
# 接收urlencoded编码
body体中:name = lqz&age = 18
# print(request.POST) 最好通过此方式获得数据
# 接收form-data编码
body体中:分两部分,一部分是数据,一部分是文件
数据部分:name=lqz&age=18
-------------------------
文件部分(二进制)
# 数据部分
# print(request.POST)
# #文件部分
# print(request.FILES)
# 接收json格式
body体中
{
"name": "lqz",
"age": 18
}
# 这里没有
print(request.POST)
# 数据在这(自行处理)
print(request.body)
return HttpResponse('ok')
五 静态文件相关
# 三种方式
# 如:在html文件中导入本地的bootstrap的样式
第一种:
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
第二种:
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}">
相当于先找到了配置文件setting.py 中的 STATIC_URL = '/static/'
那么是动态的导入模块,比如就算 STATIC_URL = '/aaaa/' 改成这样子 也能成功导入
第三种:
{% load static %}
<link rel="stylesheet" href="{% get_static_prefix %}bootstrap/css/bootstrap.min.css">
# 推荐使用第二种
# 特殊用法
# 如果导入文件的文件名过长,如图片文件,且之后要重复使用,那可以在第一次导入时取别名
{% load static %}
<img src="{% static '1036857-20180821192355156-1472752634.png' as myphotor%}" alt="">
<img src="{{ myphotor }}" alt="">
<img src="{{ myphotor }}" alt="">
<img src="{{ myphotor }}" alt="">
<img src="{{ myphotor }}" alt="">
六 inclusion_tag的使用
# 可以生成一片模板中的代码块
# 使用:6步
-第一步:在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag
-第二步:在app中创建templatetags包(包名只能是templatetags,不能改)
-第三步:在包内,新建py文件(如:my_tags.py)
-第四步:写代码(inclusion_tag)
@register.inclusion_tag('flag.html') # 在此html文件中进行渲染
def flag(num):
dic = {i: '第%s页' % i for i in range(num)}
# 固定返回的必须是字典
print(dic)
return {'dic': dic}
-第五步:在定义的第三方模板进行渲染
<ul>
{% for k,v in dic.items %}
<li>{{ v }}</li>
{% endfor %}
</ul>
-第六步:在需要返回到浏览器的模板中,动态的导入已经在第三方渲染好的模板
{% load my_tag %}
{% flag 10 %} # 传入参数导入10个页面
# 相比一般的include导入模板,这样的自定义可以传参具有更高的延展性
# 它跟tag有什么不同?
-tag需要再代码中写html的东西
返回时需要mark_safe一个html文件的内容,造成了代码的冗余
-inclusion_tag代码跟模板分离
通过@register.inclusion_tag('flag.html')选择一个第三方模板将数据在此模板渲染好了
再导入需要此模板的html文件中(解耦合)
# 作用:
与Include相似都是在一个html文件中导入某个模板中渲染好的内容,只是由于可以自定义,我们可以通过传参到自定义的函数,该函数将数据逻辑处理好进入一个第三方模板进行渲染后,将该模板导入html文件中。
七 练习
# 在请求头中创建头data 在其中可以取urlencoded,form-data,json这三种编码格式的数据
# 写一个装饰器
def data(func):
def wrapper(request, *args, **kwargs):
import json
try:
# 如果能够正常反序列化说明是Json格式,然后放入请求头data中
# 如果不是则触发异常捕获
obj = json.loads(request.body)
request.data = obj
except Exception as e:
# 这时已经说明肯定是其他编码格式(urlencoded,form-data)
obj = request.POST
# 直接添加
request.data = obj
res = func(request, *args, **kwargs) # request请求作为已知必须的传入的参数可以单独拿出来
return res
return wrapper
@data
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
else:
name = request.data.get('name') # 可直接从请求头data中取数据
pwd = request.data.get('password')
all_info = models.UserInfo.objects.all()
for user in all_info:
if name == user.name and pwd == user.password:
return HttpResponse('successful')
else:
return render(request, 'login.html', {'flag': True})
# 在响应体中添加请求头
def home(request):
obj = render(request, 'home.html', {'flag': 'abab'})
obj['name'] = 'arther'
obj['age'] = 18
return obj
# 浏览器终端显示
age: 18
Content-Length: 1392
Content-Type: text/html; charset=utf-8
Date: Mon, 12 Oct 2020 09:21:05 GMT
name: arther
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.8.4
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
# 屏蔽敏感词汇
def work(request):
if request.method == 'GET':
# 通过GET请求的方式先返回一个输入文本框的页面
return render(request, 'work.html')
import re
name = request.POST.get('name')
obj = re.findall('.*?(草你妈|傻逼|狗子|你妈)', name)
# 正则中的分组每次只能返回一个匹配内容,通过.*?的方式匹配完字符串所有的内容,匹配到一个内容后不会再重头,而是继续匹配分组内的其他字符,并以列表的方式存储
# 通过正则匹配将输入的内容中的敏感词汇放入列表
if obj:
for i in obj:
if i in name:
# 得到敏感词汇的长度
data = len(i)
name = name.replace(i, '*' * data)
return HttpResponse(name)