模版层
用pycharm创建一个名为tem的新django项目,并在该项目中创建一个名为app01的应用.
记得改模版的路径设置 'DIRS': [os.path.join(BASE_DIR, 'templates')],
暂且把中间件的csrf验证给注释掉!不然post请求会报错.
会先去项目根目录下找, 没有再根据app的注册顺序找templates目录..在该目录里找模板. static静态文件同理.
# 模版语法之传值
常见的这几种数据类型、以及类、函数都可以传,并且都能在模版中使用
但凡想在模版里调用 函数/类,都不能手动加小括号,Django模版会自动加小括号调用
模版中使用传递进来的变量需要用两个大括号包裹!
进一步取变量里的值要用.
语法 取字典的值点key, 取列表的值 <点索引>
★ 可以简单的看看这个链接: https://blog.51cto.com/u_15127596/3479503
tem下的urls.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
]
2
3
4
5
6
7
8
app01下的views.py
from django.shortcuts import render
def index(request):
# -- 常见的这几种数据类型都可以传,并且都能在模版中使用
a = {'name': 'dc', 'age': 20, 'k1': [1, {'hobby': 'football'}]}
b = 123
c = 11.11
d = 'abc'
e = True
f = [1, 2, 3, 4]
g = (5, 6, 7)
h = {8, 9, 10}
# -- 函数,类 几乎不会传函数、类,了解即可.
# 扩展,还可以传一个生成器,若传的是生成器函数,在模版里会自动加括号执行生成一个生成器对象,可以对该对象for循环.
def index():
print('Hello_index')
return 'Hello_index'
class Student():
def train(self):
print('Hello_train')
return 'Hello_train'
"""
{
'request': <WSGIRequest: GET '/index/'>,
'a': {'name': 'dc', 'age': 20},
'b': 123,
'c': 11.11,
'd': 'abc',
'e': True,
'f': [1, 2, 3, 4],
'g': (5, 6, 7),
'h': {8, 9, 10},
# -- index这个函数对象PyFunctionObject的内存地址 def+index ==> PyFunctionObject
'index': <function index.<locals>.index at 0x7fc1d5f36e50>,
# -- Student类的内存地址/类命名空间的地址
'Student': <class 'app01.views.index.<locals>.Student'>
}
"""
print(locals())
return render(request, 'index.html', locals())
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ a }} <br>
{{ b }} <br>
{{ c }} <br>
{{ d }} <br>
{{ e }} <br>
{{ f }} <br>
{{ g }} <br>
{{ h }} <br>
{# 但凡想在模版里调用 函数/类,都不能手动加括号,Django模版会自动加括号调用 #}
{# Ps: flask的模版中需要手动加 Hhh #}
{{ index }} <br>
{{ Student }} <br> {# 相当于py中Student()得到一个实例 #}
{{ Student.train }} <br> {# 相当于py中Student().train()执行实例方法 #}
<br>
{# ★!!! 模版中取值要用`.`语法 取字典的值点key,取列表的值点索引 #}
{{ a.k1.1.hobby }}
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 模版语法之过滤器
模版过滤器语法:
{{ 变量|过滤器方法:参数 }\}
★{{ ctime|date:'Y-m-d H:i:s' }\}
这个很重要,记住! 当然,你可以选择在视图中先处理, ctime = datetime.datetime.now().strftime("%Y-%m-%d")
> 过滤器还有很多,遇到了再查即可!! eg: {{ None|default:0 }} -- 是None,才会走后面赋默认值0.
app01下的views.py
from django.shortcuts import render
import datetime
def index(request):...
def tem_filter(request):
s = 'Hello World'
ctime = datetime.datetime.now() # -- ctime的值为时间戳
file_size = 125312776
s1 = '<h1>one piece</h1>'
# s1 = '<script>alert(123)</script>'
return render(request, 'tem_filter.html', locals())
"""
# -- 这样的话,模版里直接{{ s1 }}就能达到{{ s1|safe }}的效果!!!
from django.utils.safestring import mark_safe
def tem_filter(request):
s1 = '<h1>one piece</h1>'
s1 = mark_safe(s1)
return render(request, 'tem_filter.html', locals())
"""
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
tem_filter.html
<body>
{# 点进去,看源码是这样的 def length(value):#}
{{ s|length }} <br>
{# 点进去,看源码是这样的 def date(value, arg=None): ctime作为date函数的第一个参数,'Y-m-d H:i:s'是第二个参数 #}
{{ ctime|date:'Y-m-d H:i:s' }} <br>
{{ file_size|filesizeformat }} <br>
{# 在模版中默认不会执行该变量里的标签,只会当作字符串,是为了防止XSS攻击 #}
{{ s1 }} <br>
{# 加了safe过滤器就会执行该变量里的标签 #}
{{ s1|safe }}
</body>
2
3
4
5
6
7
8
9
10
11
# 模版语法之标签
app01下的views.py
def tag(request):
name_l = ['egon', 'jason', 'kevin', 'ly']
user_dic = {'name': 'dc', 'age': 20}
return render(request, 'tag.html', locals())
2
3
4
tag.html
<body>
{% for name in name_l %}
{# forloop的结果是字典的样子!#}
{# counter0索引从0开始;counter序列号从1开始;first第一个,last最后一个,值为True/False#}
{# revcounter0、revcounter倒序#}
{{ forloop }} {{ name }} <br>
{% endfor %}
{% for name in name_l %}
{% if forloop.first %}
<p>{{ name }}第一</p>
{% elif forloop.last %}
<p>{{ name }}最后</p>
{% else %}
<p>{{ name }}</p>
{% endif %}
{% endfor %}
{% for k in user_dic.keys %}
{{ k }}
{% endfor %}
<br>
{% for v in user_dic.values %}
{{ v }}
{% endfor %}
<br>
{% for item in user_dic.items %}
{{ item }}
{% endfor %}
</body>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 模版语法之导入与继承
模版的导入与继承一般用在后台的管理系统,前台很少用!!
{% extends 'home.html' %} -- 模版继承
{% block xxx %}... ...{% endblock %} -- 块改写
{% include 'other.html' %} -- 模版导入
继承、导入、块改写后,组成了一个完整的文本,然后进行渲染!!
所以母模版中有title变量,继承它的模版对应的视图函数return时可以传title数据.
app01下的views.py
def home(request):
return render(request, 'home.html')
def login(request):
return render(request, 'login.html')
def reg(request):
return render(request, 'reg.html')
2
3
4
5
6
7
8
9
10
home.html
注意a标签里的链接地址!!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<title>Title</title>
{# !!! #}
{% block css %}
{% endblock %}
</head>
<body>
<br>
<div class="container-fluid">
{# 珊格系统 左3右3 #}
<div class="row">
<div class="col-md-3">
{# 列表组 #}
<div class="list-group">
<button type="button" class="list-group-item">
<a href="/home/">首页</a>
</button>
<button type="button" class="list-group-item">
<a href="/login/">登陆</a>
</button>
<button type="button" class="list-group-item">
<a href="/reg/">注册</a>
</button>
</div>
</div>
<div class="col-md-3">
{# 巨幕 #}
<div class="jumbotron">
{# !!! block包含起来的这部分表明是会变化的 xxx是给这个块起的名字!#}
{% block xxx %}
<h2>Hello,world!</h2>
{% endblock %}
</div>
</div>
</div>
</div>
{# !!! #}
{% block js %}
{% endblock %}
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
other.html
<br>
<p>导入other.html里的代码到此处</p>
2
login.html
{% extends 'home.html' %}
{% block xxx %}
<h2>登陆!!</h2>
{# 将other.html里的代码放在这里!! #}
{% include 'other.html' %}
{% endblock %}
{% block css %}
<style>
h2 {
color: brown;
}
</style>
{% endblock %}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
reg.html
{% extends 'home.html' %}
{% block css %}
<style>
h2 {
color: orange;
}
</style>
{% endblock %}
{% block xxx %}
<h2>注册!!</h2>
{% endblock %}
2
3
4
5
6
7
8
9
10
11
12
13
点击左侧的首页
点击左侧的登陆
点击左侧的注册
# 补充
# 模版的本质
"""
模版查找顺序
模版处理本质:
读取login.html的内容,哪怕是login.txt也是可以的;
渲染完成后,生成了字符串,再返回给浏览器!
注: js里应用模版语法,js代码位置不同,呈现的结果也不同..
"""
from django.shortcuts import render
def index(request):
# a.找到login.html并读取内容. 问题:去哪里找?
# 1> 默认先去setting.TEPLATES.DIRS指定的路径中找.一般会在项目根目录下创建一个templates目录.放公共的模版.
# 2> 按照app的注册顺序,去每个app中找它的templates目录!再去该目录中找对应模版!
# ★ 原则:多app的情况,会在app的templates目录下再嵌套一层命名为app名字的目录..该目录下放模版!!
# 扩展,Django内置的app也有一些模版,比如admin这个app的404页面.想要覆盖掉,在项目根目录下,templates/admin/404.html
# b.渲染 得到替换完成的字符串
# c.将渲染完成的文本放到<响应体>里返回给浏览器
return render(request, 'api/index.html')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 自定义模版功能
准备工作:
1> 保证app已经注册
2> 在app中创建一个名为templatetags的目录 (必须叫做templatetags)
3> 在该目录下创建一个文件,任意命名 此处命名为jp.py
Ps: 我们想将数据中的名字全部转变成大写..
若在视图函数中处理,会循环一次,传给模版后,又会循环一次..共两次. 若使用过滤器在模版中处理,只需对数据渲染一次.
结果如下:
那问题来了, 这三种自定义模版功能的方式, 什么时候用哪个呢?
"""
filter的应用场景 注意,filter可以作为模版中if的条件
1> 数据处理,参数只有1-2个时
2> 模版中运行了if条件进行数据处理 只能用filter,其它的语法不支持
"""
Django模版中进行了if判断,判断的逻辑很复杂.比如还需读取文件来判断等.写在模版中很费劲.
可以利用filter来处理.. {% if n8|func0 %}
调用filter装饰的函数func0,在函数体里经过逻辑处理后,返回True或者False.
"""
simple_tag的应用场景: 参数无限制 & 返回的是文本内容 注意,它不能作为模版中if的条件
"""
返回什么,页面上就显示什么!
"""
inclusion_tag的应用场景: 参数无限制 & 返回的是一个字典
"""
返回的字典可以在html片段中引用.然后将该html片段在页面上展示.
比如:根据用户权限不同显示不同的菜单.
filter只支持两个参数,可作为if的条件,simple_tag和inclusion_tag不能作为if的条件!
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23