Django 路由层,视图层,模板层

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 - - >

猜你喜欢

转载自www.cnblogs.com/bubu99/p/10258417.html