MVC与MTV模型
一、MVC
Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的、松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),视图负责与用户的交互(页面),控制器接受用户的输入调用模型和视图完成用户的请求,其示意图如下所示:
二、MTV
Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同,Django的MTV分别是:
- M 代表模型(Model): 负责业务对象和数据库的关系映射(ORM)。
- T 代表模板 (Template):负责如何把页面展示给用户(html)。
- V 代表视图(View): 负责业务逻辑,并在适当时候调用Model和Template。
- 除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的View处理,View再调用相应的Model和Template,MTV的响应模式如下所示:
Django的下载与基本命令
- 下载Django:pip3 install django==2.0.1
- 创建一个django project: django-admin.py startproject luffy
- 在mysite目录下创建应用:python manage.py startapp app01
- 启动django项目:python manage.py runserver 8080 我们访问:http://127.0.0.1:8080/时就可以看到:
一、文件介绍
- manage.py ----- Django项目里面的工具,通过它可以调用django shell和数据库等。
- settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。
- urls.py ----- 负责把URL模式映射到应用程序。
静态文件
1
2
3
4
5
|
#在settings.py中:
STATIC_URL
=
'/static/'
STATICFILES_DIRS
=
(
os.path.join(BASE_DIR,
'static'
),
)
|
路由
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于客户端发来的某个URL调用哪一段逻辑代码对应执行。
一、简单的路由配置
- 若要从URL 中捕获一个值,只需要在它周围放置一对圆括号。
- 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
- 每个正则表达式前面的'r' 是可选的但是建议加上。它告诉Python 这个字符串是“原始的” —— 字符串中任何字符都不应该转义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
# 在urls.py中:
from
django.urls
import
path,re_path
from
app01
import
views
# 路由配置: 路径--------->视图函数
urlpatterns
=
[
path(
'admin/'
, admin.site.urls),
#无名分组:捕获的值作为位置参数传递给视图函数
re_path(r
'^articles/([0-9]{4})/$'
, views.year_archive),
#year_archive(request,'2009')
re_path(r
'^articles/([0-9]{4})/([0-9]{2})/$'
, views.month_archive),
# month_archive(request,'2009','12')
re_path(r
'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$'
, views.article_detail),
# month_archive(request,'2009','12','1'),# month_archive(request,'2009','12','13')
#有名分组:捕获的值作为关键字参数传递给视图函数
re_path(r
'^articles/(?P<year>[0-9]{4})/$'
, views.year_archive),
# month_archive(request, year='2005')
re_path(r
'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$'
, views.month_archive),
# month_archive(request, year='2005', month='03')
re_path(r
'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$'
, views.article_detail),
# month_archive(request, year='2003', month='03', day='03')
]
|
二、分发
1
2
3
4
5
6
7
8
9
10
11
|
# 在urls.py中:
from
django.urls
import
path, re_path, include
urlpatterns
=
[
path(
'admin/'
, admin.site.urls),
# 分发
re_path(r
"^app01/"
, include(
"app01.urls"
)),
re_path(r
"^app02/"
, include(
"app02.urls"
)),
re_path(r
"^"
, include(
"app01.urls"
)),
]
|
三、反向解析
获得URL 的最终形式,,对于不同层级,Django 提供不同的工具用于URL 反查:
- 在模板中:使用url 模板标签。
- 在Python 代码中:使用from django.urls import reverse
1
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
|
# 在urls.py中:
from
django.urls
import
path,re_path,include
from
app01
import
views
urlpatterns
=
[
path(
'admin/'
, admin.site.urls),
# 反向解析
path(
'login.html/'
,views.login,name
=
"Log"
),
re_path(r
'^articles/([0-9]{4})/$'
, views.year_archive, name
=
'news-year-archive'
),
]
# 在模板中:注意参数
"""
<form action="{% url 'Log' %}" method="post"></form>
<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>
<!--多个参数-->
<a href="{% url "n4" i1 i2 %}">编辑</a>
"""
#在views.py中:
from
django.urls
import
reverse
from
django.shortcuts
import
render,HttpResponse,redirect
def
redirect_to_year(request):
# 无参
url
=
reverse(
'Log'
)
print
(url)
#有参
year
=
2006
url99
=
reverse(
'news-year-archive'
, args
=
(year,))
print
(url99)
return
HttpResponse(
'OK'
)
|
四、名称空间
命名空间(英语:Namespace)是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。我们在开发项目时,会经常使用name属性反解出URL,当不小心在不同的app的urls中定义相同的name时,可能会导致URL反解错误,为了避免这种事情发生,引入了命名空间。
1
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
|
# 在urls.py中:
from
django.urls
import
path, re_path, include
urlpatterns
=
[
path(
'admin/'
, admin.site.urls),
# 分发
re_path(r
"^app01/"
, include(
"app01.urls"
)),
re_path(r
"^"
, include(
"app01.urls"
)),
# 两个应用中,URL 模式名字一样时:
re_path(r
"^app01/"
, include((
"app01.urls"
,
"app01"
))),
re_path(r
"^app02/"
, include((
"app02.urls"
,
"app02"
))),
]
#app01中的urls.py
from
django.urls
import
path,re_path
from
app01
import
views
urlpatterns
=
[
re_path(
"index/"
,views.index,name
=
"index"
)
]
#app02中的urls.py
from
django.urls
import
path,re_path
from
app02
import
views
urlpatterns
=
[
re_path(
"index/"
,views.index,name
=
"index"
)
]
#app01中的views.py
from
django.shortcuts
import
render,HttpResponse
from
django.urls
import
reverse
def
index(reqeust):
return
HttpResponse(reverse(
"app01:index"
))
#app02中的views.py
from
django.shortcuts
import
render,HttpResponse
from
django.urls
import
reverse
def
index(reqeust):
return
HttpResponse(reverse(
"app02:index"
))
|
五、django2.0版的path
1、基本实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# 在urls.py中:
from
django.urls
import
path, re_path
from
app01
import
views
urlpatterns
=
[
re_path(
'articles/(?P<year>[0-9]{4})/'
, views.year_archive),
re_path(
'article/(?P<article_id>[a-zA-Z0-9]+)/detail/'
, views.detail_view),
re_path(
'articles/(?P<article_id>[a-zA-Z0-9]+)/edit/'
, views.edit_view),
re_path(
'articles/(?P<article_id>[a-zA-Z0-9]+)/delete/'
, views.delete_view),
]
"""
1.函数 year_archive 中year参数是字符串类型的
2.三个路由中article_id都是同样的正则表达式,但是你需要写三遍,当之后article_id规则改变后,需要同时修改三处代码,
在Django2.0中,可以使用 path 解决以上的两个问题。
"""
urlpatterns
=
[
path(
'articles/2003/'
, views.special_case_2003),
path(
'articles/<int:year>/'
, views.year_archive),
path(
'articles/<int:year>/<int:month>/'
, views.month_archive),
path(
'articles/<int:year>/<int:month>/<slug>/'
, views.article_detail),
]
|
2、基本规则
- 使用尖括号(<>)从url中捕获值。
- 捕获值中可以包含一个转化器类型(converter type),比如使用 捕获一个整数变量。若果没有转化器,将匹配任何字符串,当然也包括了 / 字符。
- 无需添加前导斜杠。
3、path转化器
Django默认支持以下5个转化器:
- str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
- int,匹配正整数,包含0。
- slug,匹配字母、数字以及横杠、下划线组成的字符串。
- uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
- path,匹配任何非空字符串,包含了路径分隔符
4、注册自定义转化器
对于一些复杂或者复用的需要,可以定义自己的转化器。转化器是一个类或接口,它的要求有三点:
- regex 类属性,字符串类型
- to_python(self, value) 方法,value是由类属性 regex 所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中。
- to_url(self, value) 方法,和 to_python 相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# urls.py:
from
django.urls
import
register_converter, path
from
app01
import
yearconvert,views
#使用register_converter 将其注册到URL配置中:
register_converter(yearconvert.FourDigitYearConverter,
'yyyy'
)
urlpatterns
=
[
path(
'articles/<yyyy:year>/'
, views.year_archive),
]
#app01.yearconvert.py:
class
FourDigitYearConverter:
regex
=
'[0-9]{4}'
#规则
def
to_python(
self
, value):
return
int
(value)
# 在这转换了类型
def
to_url(
self
, value):
return
'%04d'
%
value
#app01.views.py:
from
django.shortcuts
import
render,HttpResponse,redirect
def
year_archive(request,year):
print
(year,
type
(year))
return
HttpResponse(
'ok'
)
|
视图
一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是任何东西都可以。无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你的Python目录下面。除此之外没有更多的要求了。为了将代码放在某处,约定是将视图放置在项目或应用程序目录中的名为views.py的文件中。
一、HttpRequest对象
django将请求报文中的请求行、首部信息、内容主体封装成 HttpRequest 类中的属性。
1.request属性
1
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
"""
1.HttpRequest.GET
一个类似于字典的对象,包含 HTTP GET 的所有参数。详情请参考 QueryDict 对象。
2.HttpRequest.POST
一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成 QueryDict 对象。
POST 请求可以带有空的 POST 字典 —— 如果通过 HTTP POST 方法发送一个表单,但是表单中没有任何的数据,QueryDict 对象依然会被创建。
因此,不应该使用 if request.POST 来检查使用的是否是POST 方法;应该使用 if request.method == "POST"
另外:如果使用 POST 上传文件的话,文件信息将包含在 FILES 属性中。
注意:键值对的值是多个的时候,比如checkbox类型的input标签,select标签,需要用:
request.POST.getlist("hobby")
3.HttpRequest.body
一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,例如:二进制图片、XML,Json等。
但是,如果要处理表单数据的时候,推荐还是使用 HttpRequest.POST 。
4.HttpRequest.path
一个字符串,表示请求的路径组件(不含域名)。
例如:"/music/bands/the_beatles/"
5.HttpRequest.method
一个字符串,表示请求使用的HTTP 方法。必须使用大写。
例如:"GET"、"POST"
6.HttpRequest.encoding
一个字符串,表示提交的数据的编码方式(如果为 None 则表示使用 DEFAULT_CHARSET 的设置,默认为 'utf-8')。
这个属性是可写的,你可以修改它来修改访问表单数据使用的编码。
接下来对属性的任何访问(例如从 GET 或 POST 中读取数据)将使用新的 encoding 值。
如果你知道表单数据的编码不是 DEFAULT_CHARSET ,则使用它。
7.HttpRequest.META
一个标准的Python 字典,包含所有的HTTP 首部。具体的头部信息取决于客户端和服务器,下面是一些示例:
CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
CONTENT_TYPE —— 请求的正文的MIME 类型。
HTTP_ACCEPT —— 响应可接收的Content-Type。
HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
HTTP_HOST —— 客服端发送的HTTP Host 头部。
HTTP_REFERER —— Referring 页面。
HTTP_USER_AGENT —— 客户端的user-agent 字符串。
QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
REMOTE_ADDR —— 客户端的IP 地址。
REMOTE_HOST —— 客户端的主机名。
REMOTE_USER —— 服务器认证后的用户。
REQUEST_METHOD —— 一个字符串,例如"GET" 或"POST"。
SERVER_NAME —— 服务器的主机名。
SERVER_PORT —— 服务器的端口(是一个字符串)。
从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,请求中的任何 HTTP 首部转换为 META 的键时,
都会将所有字母大写并将连接符替换为下划线最后加上 HTTP_ 前缀。
所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。
8.HttpRequest.FILES
一个类似于字典的对象,包含所有的上传文件信息。
FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会
包含数据。否则,FILES 将为一个空的类似于字典的对象。
9.HttpRequest.COOKIES
一个标准的Python 字典,包含所有的cookie。键和值都为字符串。
10.HttpRequest.session
一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django 启用会话的支持时才可用。
完整的细节参见会话的文档。
11.HttpRequest.user(用户认证组件下使用)
一个 AUTH_USER_MODEL 类型的对象,表示当前登录的用户。
如果用户当前没有登录,user 将设置为 django.contrib.auth.models.AnonymousUser 的一个实例。你可以通过 is_authenticated() 区分它们。
例如:
if request.user.is_authenticated():
# Do something for logged-in users.
else:
# Do something for anonymous users.
user 只有当Django 启用 AuthenticationMiddleware 中间件时才可用。
-------------------------------------------------------------------------------------
匿名用户
class models.AnonymousUser
django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,但具有下面几个不同点:
id 永远为None。
username 永远为空字符串。
get_username() 永远返回空字符串。
is_staff 和 is_superuser 永远为False。
is_active 永远为 False。
groups 和 user_permissions 永远为空。
is_anonymous() 返回True 而不是False。
is_authenticated() 返回False 而不是True。
set_password()、check_password()、save() 和delete() 引发 NotImplementedError。
New in Django 1.8:
新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。
"""
|
2.request常用方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
"""
1.HttpRequest.get_full_path()
返回 path,如果可以将加上查询字符串。
例如:"/music/bands/the_beatles/?print=true"
2.HttpRequest.is_ajax()
如果请求是通过XMLHttpRequest 发起的,则返回True,方法是检查 HTTP_X_REQUESTED_WITH 相应的首部是否是字符串'XMLHttpRequest'。
大部分现代的 JavaScript 库都会发送这个头部。如果你编写自己的 XMLHttpRequest 调用(在浏览器端),你必须手工设置这个值来让 is_ajax() 可以工作。
如果一个响应需要根据请求是否是通过AJAX 发起的,并且你正在使用某种形式的缓存例如Django 的 cache middleware,
你应该使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 装饰你的视图以让响应能够正确地缓存。
"""
|
二、HttpResponse对象
响应对象主要有三种形式:
- HttpResponse():HttpResponse()括号内直接跟一个具体的字符串作为响应体,比较直接很简单,所以这里主要介绍后面两种形式。
- render():render方法就是将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面作为响应体。
- redirect():重定向一个URL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
"""
render(request, template_name[, context])
结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。
参数:
request: 用于生成响应的请求对象。
template_name:要使用的模板的完整名称,可选的参数
context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。
render方法就是将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面作为响应体。
"""
return
render(request,
"index.html"
,{
"timer"
:ctime})
# index.html 模板文件
# return render(request, "index.html", locals()) #
# HttpResponse
return
HttpResponse(reverse(
"app01:index"
))
return
HttpResponse(
"<h1>OK</h1>"
)
#redirect
return
redirect(
"/index/"
)
return
redirect(
'http://baidu.com/'
)
|
模板
一、模板语法之变量
在 Django 模板中遍历复杂数据结构的关键是句点字符, 语法: {{var_name}}
1
2
3
4
5
6
|
<h4>{{s}}<
/
h4>
<h4>列表:{{ l.
0
}}<
/
h4>
<h4>列表:{{ l.
2
}}<
/
h4>
<h4>字典:{{ dic.name }}<
/
h4>
<h4>日期:{{ date.year }}<
/
h4>
<h4>类对象列表:{{ person_list.
0.name
}}<
/
h4>
|
二、模板之过滤器
语法:{{obj|filter__name:param}}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
"""
default:如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值。例如:
{{ value|default:"nothing" }}
length:返回值的长度。它对字符串和列表都起作用。例如:
{{ value|length }} 如果 value 是 ['a', 'b', 'c', 'd'],那么输出是 4。
filesizeformat:将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。例如:
{{ value|filesizeformat }} 如果 value 是 123456789,输出将会是 117.7 MB。
date:如果 value=datetime.datetime.now()
{{ value|date:"Y-m-d" }}
slice:如果 value="hello world"
{{ value|slice:"2:-1" }}
truncatechars:
如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。
参数:要截断的字符数
{{ value|truncatechars:9 }}
safe:Django的模板中会对HTML标签和JS等语法标签进行自动转义,这样是为了安全。如果不希望HTML元素被转义,可以这样:
value="<a href="">点击</a>"
{{ value|safe}}
"""
|
这里简单介绍一些常用的模板的过滤器,更多详见
三、模板之标签
标签看起来像是这样的: {% tag %}。标签比变量更加复杂:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。一些标签需要开始和结束标签 (例如{% tag %} ...标签 内容 ... {% endtag %})。
1、for标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
"""
遍历每一个元素:
{% for person in person_list %}
<p>{{ person.name }}</p>
{% endfor %}
可以利用{% for obj in list reversed %}反向完成循环。
遍历一个字典:
{% for key,val in dic.items %}
<p>{{ forloop.counter }} {{ key }}:{{ val }}</p>
{% endfor %}
注:循环序号可以通过{{ forloop }}显示
forloop.counter The current iteration of the loop (1-indexed)
forloop.counter0 The current iteration of the loop (0-indexed)
forloop.revcounter The number of iterations from the end of the loop (1-indexed)
forloop.revcounter0 The number of iterations from the end of the loop (0-indexed)
forloop.first True if this is the first time through the loop
forloop.last True if this is the last time through the loop
"""
|
2、for ... empty
1
2
3
4
5
6
|
<!
-
-
for
标签带有一个可选的{
%
empty
%
} 从句,以便在给出的组是空的或者没有被找到时,可以有所操作。
-
-
>
{
%
for
person
in
person_list
%
}
<p>{{ forloop.counter0 }} {{ person.name }} , {{ person.age }}<
/
p>
{
%
empty
%
}
<p>列表为空<
/
p>
{
%
endfor
%
}
|
3、if 标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<!
-
-
注意:
filter
可以用在
if
等语句后,simple_tag不可以
-
-
>
{
%
if
i|multi_fliter:
10
>
100
%
}
<p>
100
<
/
p>
{
%
else
%
}
<p>{{ i }}<
/
p>
{
%
endif
%
}
<!
-
-
多分支
-
-
>
{
%
if
num >
100
or
num <
0
%
}
<p>无效<
/
p>
{
%
elif
num >
80
and
num <
100
%
}
<p>优秀<
/
p>
{
%
else
%
}
<p>凑活吧<
/
p>
{
%
endif
%
}
|
4、with
1
2
3
4
5
|
<!
-
-
使用一个简单地名字缓存一个复杂的变量
-
-
>
{
%
with person_list.
1.name
as n
%
}
{{ n }}
{{ n }}
{
%
endwith
%
}
|
5、csrf_token
1
2
3
4
5
|
<form action
=
"
" method="
post">
{
%
csrf_token
%
} <!
-
-
这个标签用于跨站请求伪造保护
-
-
>
<
input
type
=
"text"
name
=
"user"
>
<
input
type
=
"submit"
>
<
/
form>
|
四、自定义标签和过滤器
1
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
46
47
48
49
50
51
52
53
|
"""
1、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.
2、在app中创建templatetags包(包名只能是templatetags)
3、创建任意 .py 文件,如:my_tags.py
4、在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py
5、使用simple_tag和filter(如何调用)
注意:filter可以用在if等语句后,simple_tag不可以
"""
#settings.py
INSTALLED_APPS
=
[
'django.contrib.admin'
,
'django.contrib.auth'
,
'django.contrib.contenttypes'
,
'django.contrib.sessions'
,
'django.contrib.messages'
,
'django.contrib.staticfiles'
,
"app01"
,
#配置当前app
]
# app01.templatetags.my_tags.py
from
django
import
template
from
django.utils.safestring
import
mark_safe
register
=
template.Library()
# register的名字是固定的,不可改变
@register
.
filter
#自定义过滤器最多2个参数
def
multi_fliter(v1, v2):
return
v1
*
v2
@register
.simple_tag
#自定义标签,没有参数个数限制
def
multi_tag(v1, v2, v3):
return
v1
*
v2
*
v3
@register
.simple_tag
def
my_input(
id
, arg):
result
=
"<input type='text' id='%s' class='%s' />"
%
(
id
, arg,)
return
mark_safe(result)
#模板中:
"""
{% load my_tags %} <!--注意:这块更改过要重启项目-->
# num = 8
<p>{{ num|multi_fliter:20 }}</p>
<p>{% multi_tag 7 9 6 %}</p>
<!--注意:filter可以用在if等语句后,simple_tag不可以-->
{% if num|multi_fliter:10 > 100 %}
<p>100</p>
{% else %}
<p>{{ num }}</p>
{% endif %}
"""
|
五、模板继承 (extend)
- 不能在一个模版中定义多个相同名字的 block 标签。
- 为了更好的可读性,你也可以给你的 {% endblock %} 标签一个 名字 。例如:{% block content %}...{% endblock content %}
- 子模版不必定义全部父模版中的blocks
- {% extends 'base.html' %}
1、制作模板
1
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
|
<!
-
-
模版 base.html
-
-
>
<!DOCTYPE html>
<html lang
=
"en"
>
<head>
<meta charset
=
"UTF-8"
>
{
%
block title
%
}
<title>base<
/
title>
{
%
endblock
%
}
{
%
block css
%
} {
%
endblock
%
}
<
/
head>
<body>
<div
class
=
"header"
><
/
div>
<div
class
=
"container"
>
<div
class
=
"row"
>
<div
class
=
"col-md-3"
>
{
%
include
'left1.html'
%
} <!
-
-
引入某个区域
-
-
>
{
%
include
'left2.html'
%
} <!
-
-
引入某个区域
-
-
>
<
/
div>
<div
class
=
"col-md-9"
>
{
%
block con
%
}
<h4>content<
/
h4>
{
%
endblock content
%
} <!
-
-
更好的可读性
-
-
>
<
/
div>
<
/
div>
<
/
div>
{
%
block js
%
}{
%
endblock
%
}
<
/
body>
<
/
html>
|
2、继承模板
1
2
3
4
5
6
7
8
9
10
11
12
|
{
%
extends
'base.html'
%
} <!
-
-
它必须是模版中的第一个标签。
-
-
>
{
%
block title
%
}
<title>orders<
/
title>
{
%
endblock
%
}
{
%
block con
%
}
{{ block.
super
}} <!
-
-
获取模板中con的内容
-
-
>
<h4>订单<
/
h4>
{
%
endblock con
%
}
<!
-
-
order.html
-
-
>
|
MVC与MTV模型
一、MVC
Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的、松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),视图负责与用户的交互(页面),控制器接受用户的输入调用模型和视图完成用户的请求,其示意图如下所示:
二、MTV
Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同,Django的MTV分别是:
- M 代表模型(Model): 负责业务对象和数据库的关系映射(ORM)。
- T 代表模板 (Template):负责如何把页面展示给用户(html)。
- V 代表视图(View): 负责业务逻辑,并在适当时候调用Model和Template。
- 除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的View处理,View再调用相应的Model和Template,MTV的响应模式如下所示:
Django的下载与基本命令
- 下载Django:pip3 install django==2.0.1
- 创建一个django project: django-admin.py startproject luffy
- 在mysite目录下创建应用:python manage.py startapp app01
- 启动django项目:python manage.py runserver 8080 我们访问:http://127.0.0.1:8080/时就可以看到:
一、文件介绍
- manage.py ----- Django项目里面的工具,通过它可以调用django shell和数据库等。
- settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。
- urls.py ----- 负责把URL模式映射到应用程序。
静态文件
1
2
3
4
5
|
#在settings.py中:
STATIC_URL
=
'/static/'
STATICFILES_DIRS
=
(
os.path.join(BASE_DIR,
'static'
),
)
|
路由
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于客户端发来的某个URL调用哪一段逻辑代码对应执行。
一、简单的路由配置
- 若要从URL 中捕获一个值,只需要在它周围放置一对圆括号。
- 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
- 每个正则表达式前面的'r' 是可选的但是建议加上。它告诉Python 这个字符串是“原始的” —— 字符串中任何字符都不应该转义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
# 在urls.py中:
from
django.urls
import
path,re_path
from
app01
import
views
# 路由配置: 路径--------->视图函数
urlpatterns
=
[
path(
'admin/'
, admin.site.urls),
#无名分组:捕获的值作为位置参数传递给视图函数
re_path(r
'^articles/([0-9]{4})/$'
, views.year_archive),
#year_archive(request,'2009')
re_path(r
'^articles/([0-9]{4})/([0-9]{2})/$'
, views.month_archive),
# month_archive(request,'2009','12')
re_path(r
'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$'
, views.article_detail),
# month_archive(request,'2009','12','1'),# month_archive(request,'2009','12','13')
#有名分组:捕获的值作为关键字参数传递给视图函数
re_path(r
'^articles/(?P<year>[0-9]{4})/$'
, views.year_archive),
# month_archive(request, year='2005')
re_path(r
'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$'
, views.month_archive),
# month_archive(request, year='2005', month='03')
re_path(r
'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$'
, views.article_detail),
# month_archive(request, year='2003', month='03', day='03')
]
|
二、分发
1
2
3
4
5
6
7
8
9
10
11
|
# 在urls.py中:
from
django.urls
import
path, re_path, include
urlpatterns
=
[
path(
'admin/'
, admin.site.urls),
# 分发
re_path(r
"^app01/"
, include(
"app01.urls"
)),
re_path(r
"^app02/"
, include(
"app02.urls"
)),
re_path(r
"^"
, include(
"app01.urls"
)),
]
|
三、反向解析
获得URL 的最终形式,,对于不同层级,Django 提供不同的工具用于URL 反查:
- 在模板中:使用url 模板标签。
- 在Python 代码中:使用from django.urls import reverse
1
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
|
# 在urls.py中:
from
django.urls
import
path,re_path,include
from
app01
import
views
urlpatterns
=
[
path(
'admin/'
, admin.site.urls),
# 反向解析
path(
'login.html/'
,views.login,name
=
"Log"
),
re_path(r
'^articles/([0-9]{4})/$'
, views.year_archive, name
=
'news-year-archive'
),
]
# 在模板中:注意参数
"""
<form action="{% url 'Log' %}" method="post"></form>
<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>
<!--多个参数-->
<a href="{% url "n4" i1 i2 %}">编辑</a>
"""
#在views.py中:
from
django.urls
import
reverse
from
django.shortcuts
import
render,HttpResponse,redirect
def
redirect_to_year(request):
# 无参
url
=
reverse(
'Log'
)
print
(url)
#有参
year
=
2006
url99
=
reverse(
'news-year-archive'
, args
=
(year,))
print
(url99)
return
HttpResponse(
'OK'
)
|
四、名称空间
命名空间(英语:Namespace)是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。我们在开发项目时,会经常使用name属性反解出URL,当不小心在不同的app的urls中定义相同的name时,可能会导致URL反解错误,为了避免这种事情发生,引入了命名空间。
1
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
|
# 在urls.py中:
from
django.urls
import
path, re_path, include
urlpatterns
=
[
path(
'admin/'
, admin.site.urls),
# 分发
re_path(r
"^app01/"
, include(
"app01.urls"
)),
re_path(r
"^"
, include(
"app01.urls"
)),
# 两个应用中,URL 模式名字一样时:
re_path(r
"^app01/"
, include((
"app01.urls"
,
"app01"
))),
re_path(r
"^app02/"
, include((
"app02.urls"
,
"app02"
))),
]
#app01中的urls.py
from
django.urls
import
path,re_path
from
app01
import
views
urlpatterns
=
[
re_path(
"index/"
,views.index,name
=
"index"
)
]
#app02中的urls.py
from
django.urls
import
path,re_path
from
app02
import
views
urlpatterns
=
[
re_path(
"index/"
,views.index,name
=
"index"
)
]
#app01中的views.py
from
django.shortcuts
import
render,HttpResponse
from
django.urls
import
reverse
def
index(reqeust):
return
HttpResponse(reverse(
"app01:index"
))
#app02中的views.py
from
django.shortcuts
import
render,HttpResponse
from
django.urls
import
reverse
def
index(reqeust):
return
HttpResponse(reverse(
"app02:index"
))
|
五、django2.0版的path
1、基本实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# 在urls.py中:
from
django.urls
import
path, re_path
from
app01
import
views
urlpatterns
=
[
re_path(
'articles/(?P<year>[0-9]{4})/'
, views.year_archive),
re_path(
'article/(?P<article_id>[a-zA-Z0-9]+)/detail/'
, views.detail_view),
re_path(
'articles/(?P<article_id>[a-zA-Z0-9]+)/edit/'
, views.edit_view),
re_path(
'articles/(?P<article_id>[a-zA-Z0-9]+)/delete/'
, views.delete_view),
]
"""
1.函数 year_archive 中year参数是字符串类型的
2.三个路由中article_id都是同样的正则表达式,但是你需要写三遍,当之后article_id规则改变后,需要同时修改三处代码,
在Django2.0中,可以使用 path 解决以上的两个问题。
"""
urlpatterns
=
[
path(
'articles/2003/'
, views.special_case_2003),
path(
'articles/<int:year>/'
, views.year_archive),
path(
'articles/<int:year>/<int:month>/'
, views.month_archive),
path(
'articles/<int:year>/<int:month>/<slug>/'
, views.article_detail),
]
|
2、基本规则
- 使用尖括号(<>)从url中捕获值。
- 捕获值中可以包含一个转化器类型(converter type),比如使用 捕获一个整数变量。若果没有转化器,将匹配任何字符串,当然也包括了 / 字符。
- 无需添加前导斜杠。
3、path转化器
Django默认支持以下5个转化器:
- str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
- int,匹配正整数,包含0。
- slug,匹配字母、数字以及横杠、下划线组成的字符串。
- uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
- path,匹配任何非空字符串,包含了路径分隔符
4、注册自定义转化器
对于一些复杂或者复用的需要,可以定义自己的转化器。转化器是一个类或接口,它的要求有三点:
- regex 类属性,字符串类型
- to_python(self, value) 方法,value是由类属性 regex 所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中。
- to_url(self, value) 方法,和 to_python 相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# urls.py:
from
django.urls
import
register_converter, path
from
app01
import
yearconvert,views
#使用register_converter 将其注册到URL配置中:
register_converter(yearconvert.FourDigitYearConverter,
'yyyy'
)
urlpatterns
=
[
path(
'articles/<yyyy:year>/'
, views.year_archive),
]
#app01.yearconvert.py:
class
FourDigitYearConverter:
regex
=
'[0-9]{4}'
#规则
def
to_python(
self
, value):
return
int
(value)
# 在这转换了类型
def
to_url(
self
, value):
return
'%04d'
%
value
#app01.views.py:
from
django.shortcuts
import
render,HttpResponse,redirect
def
year_archive(request,year):
print
(year,
type
(year))
return
HttpResponse(
'ok'
)
|
视图
一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是任何东西都可以。无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你的Python目录下面。除此之外没有更多的要求了。为了将代码放在某处,约定是将视图放置在项目或应用程序目录中的名为views.py的文件中。
一、HttpRequest对象
django将请求报文中的请求行、首部信息、内容主体封装成 HttpRequest 类中的属性。
1.request属性
1
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
"""
1.HttpRequest.GET
一个类似于字典的对象,包含 HTTP GET 的所有参数。详情请参考 QueryDict 对象。
2.HttpRequest.POST
一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成 QueryDict 对象。
POST 请求可以带有空的 POST 字典 —— 如果通过 HTTP POST 方法发送一个表单,但是表单中没有任何的数据,QueryDict 对象依然会被创建。
因此,不应该使用 if request.POST 来检查使用的是否是POST 方法;应该使用 if request.method == "POST"
另外:如果使用 POST 上传文件的话,文件信息将包含在 FILES 属性中。
注意:键值对的值是多个的时候,比如checkbox类型的input标签,select标签,需要用:
request.POST.getlist("hobby")
3.HttpRequest.body
一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,例如:二进制图片、XML,Json等。
但是,如果要处理表单数据的时候,推荐还是使用 HttpRequest.POST 。
4.HttpRequest.path
一个字符串,表示请求的路径组件(不含域名)。
例如:"/music/bands/the_beatles/"
5.HttpRequest.method
一个字符串,表示请求使用的HTTP 方法。必须使用大写。
例如:"GET"、"POST"
6.HttpRequest.encoding
一个字符串,表示提交的数据的编码方式(如果为 None 则表示使用 DEFAULT_CHARSET 的设置,默认为 'utf-8')。
这个属性是可写的,你可以修改它来修改访问表单数据使用的编码。
接下来对属性的任何访问(例如从 GET 或 POST 中读取数据)将使用新的 encoding 值。
如果你知道表单数据的编码不是 DEFAULT_CHARSET ,则使用它。
7.HttpRequest.META
一个标准的Python 字典,包含所有的HTTP 首部。具体的头部信息取决于客户端和服务器,下面是一些示例:
CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
CONTENT_TYPE —— 请求的正文的MIME 类型。
HTTP_ACCEPT —— 响应可接收的Content-Type。
HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
HTTP_HOST —— 客服端发送的HTTP Host 头部。
HTTP_REFERER —— Referring 页面。
HTTP_USER_AGENT —— 客户端的user-agent 字符串。
QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
REMOTE_ADDR —— 客户端的IP 地址。
REMOTE_HOST —— 客户端的主机名。
REMOTE_USER —— 服务器认证后的用户。
REQUEST_METHOD —— 一个字符串,例如"GET" 或"POST"。
SERVER_NAME —— 服务器的主机名。
SERVER_PORT —— 服务器的端口(是一个字符串)。
从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,请求中的任何 HTTP 首部转换为 META 的键时,
都会将所有字母大写并将连接符替换为下划线最后加上 HTTP_ 前缀。
所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。
8.HttpRequest.FILES
一个类似于字典的对象,包含所有的上传文件信息。
FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会
包含数据。否则,FILES 将为一个空的类似于字典的对象。
9.HttpRequest.COOKIES
一个标准的Python 字典,包含所有的cookie。键和值都为字符串。
10.HttpRequest.session
一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django 启用会话的支持时才可用。
完整的细节参见会话的文档。
11.HttpRequest.user(用户认证组件下使用)
一个 AUTH_USER_MODEL 类型的对象,表示当前登录的用户。
如果用户当前没有登录,user 将设置为 django.contrib.auth.models.AnonymousUser 的一个实例。你可以通过 is_authenticated() 区分它们。
例如:
if request.user.is_authenticated():
# Do something for logged-in users.
else:
# Do something for anonymous users.
user 只有当Django 启用 AuthenticationMiddleware 中间件时才可用。
-------------------------------------------------------------------------------------
匿名用户
class models.AnonymousUser
django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,但具有下面几个不同点:
id 永远为None。
username 永远为空字符串。
get_username() 永远返回空字符串。
is_staff 和 is_superuser 永远为False。
is_active 永远为 False。
groups 和 user_permissions 永远为空。
is_anonymous() 返回True 而不是False。
is_authenticated() 返回False 而不是True。
set_password()、check_password()、save() 和delete() 引发 NotImplementedError。
New in Django 1.8:
新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。
"""
|
2.request常用方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
"""
1.HttpRequest.get_full_path()
返回 path,如果可以将加上查询字符串。
例如:"/music/bands/the_beatles/?print=true"
2.HttpRequest.is_ajax()
如果请求是通过XMLHttpRequest 发起的,则返回True,方法是检查 HTTP_X_REQUESTED_WITH 相应的首部是否是字符串'XMLHttpRequest'。
大部分现代的 JavaScript 库都会发送这个头部。如果你编写自己的 XMLHttpRequest 调用(在浏览器端),你必须手工设置这个值来让 is_ajax() 可以工作。
如果一个响应需要根据请求是否是通过AJAX 发起的,并且你正在使用某种形式的缓存例如Django 的 cache middleware,
你应该使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 装饰你的视图以让响应能够正确地缓存。
"""
|
二、HttpResponse对象
响应对象主要有三种形式:
- HttpResponse():HttpResponse()括号内直接跟一个具体的字符串作为响应体,比较直接很简单,所以这里主要介绍后面两种形式。
- render():render方法就是将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面作为响应体。
- redirect():重定向一个URL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
"""
render(request, template_name[, context])
结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。
参数:
request: 用于生成响应的请求对象。
template_name:要使用的模板的完整名称,可选的参数
context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。
render方法就是将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面作为响应体。
"""
return
render(request,
"index.html"
,{
"timer"
:ctime})
# index.html 模板文件
# return render(request, "index.html", locals()) #
# HttpResponse
return
HttpResponse(reverse(
"app01:index"
))
return
HttpResponse(
"<h1>OK</h1>"
)
#redirect
return
redirect(
"/index/"
)
return
redirect(
'http://baidu.com/'
)
|
模板
一、模板语法之变量
在 Django 模板中遍历复杂数据结构的关键是句点字符, 语法: {{var_name}}
1
2
3
4
5
6
|
<h4>{{s}}<
/
h4>
<h4>列表:{{ l.
0
}}<
/
h4>
<h4>列表:{{ l.
2
}}<
/
h4>
<h4>字典:{{ dic.name }}<
/
h4>
<h4>日期:{{ date.year }}<
/
h4>
<h4>类对象列表:{{ person_list.
0.name
}}<
/
h4>
|
二、模板之过滤器
语法:{{obj|filter__name:param}}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
"""
default:如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值。例如:
{{ value|default:"nothing" }}
length:返回值的长度。它对字符串和列表都起作用。例如:
{{ value|length }} 如果 value 是 ['a', 'b', 'c', 'd'],那么输出是 4。
filesizeformat:将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。例如:
{{ value|filesizeformat }} 如果 value 是 123456789,输出将会是 117.7 MB。
date:如果 value=datetime.datetime.now()
{{ value|date:"Y-m-d" }}
slice:如果 value="hello world"
{{ value|slice:"2:-1" }}
truncatechars:
如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。
参数:要截断的字符数
{{ value|truncatechars:9 }}
safe:Django的模板中会对HTML标签和JS等语法标签进行自动转义,这样是为了安全。如果不希望HTML元素被转义,可以这样:
value="<a href="">点击</a>"
{{ value|safe}}
"""
|
这里简单介绍一些常用的模板的过滤器,更多详见
三、模板之标签
标签看起来像是这样的: {% tag %}。标签比变量更加复杂:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。一些标签需要开始和结束标签 (例如{% tag %} ...标签 内容 ... {% endtag %})。
1、for标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
"""
遍历每一个元素:
{% for person in person_list %}
<p>{{ person.name }}</p>
{% endfor %}
可以利用{% for obj in list reversed %}反向完成循环。
遍历一个字典:
{% for key,val in dic.items %}
<p>{{ forloop.counter }} {{ key }}:{{ val }}</p>
{% endfor %}
注:循环序号可以通过{{ forloop }}显示
forloop.counter The current iteration of the loop (1-indexed)
forloop.counter0 The current iteration of the loop (0-indexed)
forloop.revcounter The number of iterations from the end of the loop (1-indexed)
forloop.revcounter0 The number of iterations from the end of the loop (0-indexed)
forloop.first True if this is the first time through the loop
forloop.last True if this is the last time through the loop
"""
|
2、for ... empty
1
2
3
4
5
6
|
<!
-
-
for
标签带有一个可选的{
%
empty
%
} 从句,以便在给出的组是空的或者没有被找到时,可以有所操作。
-
-
>
{
%
for
person
in
person_list
%
}
<p>{{ forloop.counter0 }} {{ person.name }} , {{ person.age }}<
/
p>
{
%
empty
%
}
<p>列表为空<
/
p>
{
%
endfor
%
}
|
3、if 标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<!
-
-
注意:
filter
可以用在
if
等语句后,simple_tag不可以
-
-
>
{
%
if
i|multi_fliter:
10
>
100
%
}
<p>
100
<
/
p>
{
%
else
%
}
<p>{{ i }}<
/
p>
{
%
endif
%
}
<!
-
-
多分支
-
-
>
{
%
if
num >
100
or
num <
0
%
}
<p>无效<
/
p>
{
%
elif
num >
80
and
num <
100
%
}
<p>优秀<
/
p>
{
%
else
%
}
<p>凑活吧<
/
p>
{
%
endif
%
}
|
4、with
1
2
3
4
5
|
<!
-
-
使用一个简单地名字缓存一个复杂的变量
-
-
>
{
%
with person_list.
1.name
as n
%
}
{{ n }}
{{ n }}
{
%
endwith
%
}
|
5、csrf_token
1
2
3
4
5
|
<form action
=
"
" method="
post">
{
%
csrf_token
%
} <!
-
-
这个标签用于跨站请求伪造保护
-
-
>
<
input
type
=
"text"
name
=
"user"
>
<
input
type
=
"submit"
>
<
/
form>
|
四、自定义标签和过滤器
1
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
46
47
48
49
50
51
52
53
|
"""
1、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.
2、在app中创建templatetags包(包名只能是templatetags)
3、创建任意 .py 文件,如:my_tags.py
4、在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py
5、使用simple_tag和filter(如何调用)
注意:filter可以用在if等语句后,simple_tag不可以
"""
#settings.py
INSTALLED_APPS
=
[
'django.contrib.admin'
,
'django.contrib.auth'
,
'django.contrib.contenttypes'
,
'django.contrib.sessions'
,
'django.contrib.messages'
,
'django.contrib.staticfiles'
,
"app01"
,
#配置当前app
]
# app01.templatetags.my_tags.py
from
django
import
template
from
django.utils.safestring
import
mark_safe
register
=
template.Library()
# register的名字是固定的,不可改变
@register
.
filter
#自定义过滤器最多2个参数
def
multi_fliter(v1, v2):
return
v1
*
v2
@register
.simple_tag
#自定义标签,没有参数个数限制
def
multi_tag(v1, v2, v3):
return
v1
*
v2
*
v3
@register
.simple_tag
def
my_input(
id
, arg):
result
=
"<input type='text' id='%s' class='%s' />"
%
(
id
, arg,)
return
mark_safe(result)
#模板中:
"""
{% load my_tags %} <!--注意:这块更改过要重启项目-->
# num = 8
<p>{{ num|multi_fliter:20 }}</p>
<p>{% multi_tag 7 9 6 %}</p>
<!--注意:filter可以用在if等语句后,simple_tag不可以-->
{% if num|multi_fliter:10 > 100 %}
<p>100</p>
{% else %}
<p>{{ num }}</p>
{% endif %}
"""
|
五、模板继承 (extend)
- 不能在一个模版中定义多个相同名字的 block 标签。
- 为了更好的可读性,你也可以给你的 {% endblock %} 标签一个 名字 。例如:{% block content %}...{% endblock content %}
- 子模版不必定义全部父模版中的blocks
- {% extends 'base.html' %}
1、制作模板
1
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
|
<!
-
-
模版 base.html
-
-
>
<!DOCTYPE html>
<html lang
=
"en"
>
<head>
<meta charset
=
"UTF-8"
>
{
%
block title
%
}
<title>base<
/
title>
{
%
endblock
%
}
{
%
block css
%
} {
%
endblock
%
}
<
/
head>
<body>
<div
class
=
"header"
><
/
div>
<div
class
=
"container"
>
<div
class
=
"row"
>
<div
class
=
"col-md-3"
>
{
%
include
'left1.html'
%
} <!
-
-
引入某个区域
-
-
>
{
%
include
'left2.html'
%
} <!
-
-
引入某个区域
-
-
>
<
/
div>
<div
class
=
"col-md-9"
>
{
%
block con
%
}
<h4>content<
/
h4>
{
%
endblock content
%
} <!
-
-
更好的可读性
-
-
>
<
/
div>
<
/
div>
<
/
div>
{
%
block js
%
}{
%
endblock
%
}
<
/
body>
<
/
html>
|
2、继承模板
1
2
3
4
5
6
7
8
9
10
11
12
|
{
%
extends
'base.html'
%
} <!
-
-
它必须是模版中的第一个标签。
-
-
>
{
%
block title
%
}
<title>orders<
/
title>
{
%
endblock
%
}
{
%
block con
%
}
{{ block.
super
}} <!
-
-
获取模板中con的内容
-
-
>
<h4>订单<
/
h4>
{
%
endblock con
%
}
<!
-
-
order.html
-
-
>
|