Django 的路由层 视图层 模板层

 

--------------------------------------------------------------经过苦难,走向欢乐。——贝多芬php


 

 Django-2的路由层(URLconf)css

 

URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于客户端发来的某个URL调用哪一段逻辑代码对应执行。html

简单的路由配置

复制代码
from django.urls import path,re_path

from app01 import views

urlpatterns = [
    re_path(r'^articles/2003/$', views.special_case_2003),
    re_path(r'^articles/([0-9]{4})/$', views.year_archive),
    re_path(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    re_path(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]
复制代码

注意:python

  • 若要从URL 中捕获一个值,只须要在它周围放置一对圆括号。
  • 不须要添加一个前导的反斜杠,由于每一个URL 都有。例如,应该是^articles 而不是 ^/articles
  • 每一个正则表达式前面的'r' 是可选的可是建议加上。它告诉Python 这个字符串是“原始的” —— 字符串中任何字符都不该该转义

示例:git

复制代码
    
    '''
 一些请求的例子:

/articles/2005/03/ 请求将匹配列表中的第三个模式。Django 将调用函数views.month_archive(request, '2005', '03')。
/articles/2005/3/ 不匹配任何URL 模式,由于列表中的第三个模式要求月份应该是两个数字。
/articles/2003/ 将匹配列表中的第一个模式不是第二个,由于模式按顺序匹配,第一个会首先测试是否匹配。请像这样自由插入一些特殊的状况来探测匹配的次序。
/articles/2003 不匹配任何一个模式,由于每一个模式要求URL 以一个反斜线结尾。
/articles/2003/03/03/ 将匹配最后一个模式。Django 将调用函数views.article_detail(request, '2003', '03', '03')。
   
    '''
复制代码

有名分组

上面的示例使用简单的、没有命名的正则表达式组(经过圆括号)来捕获URL 中的值并以位置 参数传递给视图。在更高级的用法中,可使用命名的正则表达式组来捕获URL 中的值并以关键字 参数传递给视图。程序员

在Python 正则表达式中,命名正则表达式组的语法是(?P<name>pattern),其中name 是组的名称,pattern 是要匹配的模式。ajax

下面是以上URLconf 使用命名组的重写:正则表达式

复制代码
from django.urls import path,re_path

from app01 import views

urlpatterns = [
    re_path(r'^articles/2003/$', views.special_case_2003),
    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]
复制代码

这个实现与前面的示例彻底相同,只有一个细微的差异:捕获的值做为关键字参数而不是位置参数传递给视图函数。例如:数据库

    '''
    /articles/2005/03/ 请求将调用views.month_archive(request, year='2005', month='03')函数,而不是views.month_archive(request, '2005', '03')。
    /articles/2003/03/03/ 请求将调用函数views.article_detail(request, year='2003', month='03', day='03')。

    '''

在实际应用中,这意味你的URLconf 会更加明晰且不容易产生参数顺序问题的错误 —— 你能够在你的视图函数定义中从新安排参数的顺序。固然,这些好处是以简洁为代价;django

分发

复制代码
'''
At any point, your urlpatterns can “include” other URLconf modules. This
essentially “roots” a set of URLs below other ones.

'''

from django.urls import path,re_path,include
from app01 import views

urlpatterns = [
   re_path(r'^admin/', admin.site.urls),
   re_path(r'^blog/', include('blog.urls')),
]
复制代码

反向解析

在使用Django 项目时,一个常见的需求是得到URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。人们强烈但愿不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 绝不相关的专门的URL 生成机制,由于这样容易致使必定程度上产生过时的URL。

在须要URL 的地方,对于不一样层级,Django 提供不一样的工具用于URL 反查:

  • 在模板中:使用url 模板标签。
  • 在Python 代码中:使用from django.urls import reverse()函数
     

urls.py:

复制代码
from django.conf.urls import url

from . import views

urlpatterns = [
    #...
    re_path(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
    #...
]
复制代码

在模板中:

复制代码
<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>
复制代码

在python中:

复制代码
from django.urls import reverse
from django.http import HttpResponseRedirect

def redirect_to_year(request):
    # ...
    year = 2006
    # ...
    return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))   # 同redirect("/path/")
复制代码

当命名你的URL 模式时,请确保使用的名称不会与其它应用中名称冲突。若是你的URL 模式叫作comment,而另一个应用中也有一个一样的名称,当你在模板中使用这个名称的时候不能保证将插入哪一个URL。在URL 名称中加上一个前缀,好比应用的名称,将减小冲突的可能。咱们建议使用myapp-comment 而不是comment

名称空间

命名空间(英语:Namespace)是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不一样命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,由于已有的定义都处于其它命名空间中。

因为name没有做用域,Django在反解URL时,会在项目全局顺序搜索,当查找到第一个name指定URL时,当即返回
咱们在开发项目时,会常用name属性反解出URL,当不当心在不一样的app的urls中定义相同的name时,可能会致使URL反解错误,为了不这种事情发生,引入了命名空间。

project的urls.py:

urlpatterns = [
    re_path(r'^admin/', admin.site.urls),
    re_path(r'^app01/', include("app01.urls",namespace="app01")),
    re_path(r'^app02/', include("app02.urls",namespace="app02")),
]

app01.urls:

urlpatterns = [
    re_path(r'^index/', index,name="index"),
]

app02.urls:

urlpatterns = [
    re_path(r'^index/', index,name="index"),
]

app01.views 

from django.core.urlresolvers import reverse

def index(request):

    return  HttpResponse(reverse("app01:index"))

app02.views

from django.core.urlresolvers import reverse

def index(request):

    return  HttpResponse(reverse("app02:index"))

django2.0版的path

思考状况以下:

urlpatterns = [  
    re_path('articles/(?P<year>[0-9]{4})/', year_archive),  
    re_path('article/(?P<article_id>[a-zA-Z0-9]+)/detail/', detail_view),  
    re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/edit/', edit_view),  
    re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/delete/', delete_view),  
]

考虑下这样的两个问题:

第一个问题,函数 year_archive 中year参数是字符串类型的,所以须要先转化为整数类型的变量值,固然year=int(year) 不会有诸如如TypeError或者ValueError的异常。那么有没有一种方法,在url中,使得这一转化步骤能够由Django自动完成?

第二个问题,三个路由中article_id都是一样的正则表达式,可是你须要写三遍,当以后article_id规则改变后,须要同时修改三处代码,那么有没有一种方法,只需修改一处便可?

在Django2.0中,可使用 path 解决以上的两个问题。

基本示例

这是一个简单的例子:

复制代码
from django.urls import path  
from . import views  
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),  
]  
复制代码

基本规则:

  • 使用尖括号(<>)从url中捕获值。
  • 捕获值中能够包含一个转化器类型(converter type),好比使用 <int:name> 捕获一个整数变量。若果没有转化器,将匹配任何字符串,固然也包括了 / 字符。
  • 无需添加前导斜杠。

如下是根据 2.0官方文档 而整理的示例分析表:

path转化器

文档原文是Path converters,暂且翻译为转化器。

Django默认支持如下5个转化器:

  • str,匹配除了路径分隔符(/)以外的非空字符串,这是默认的形式
  • int,匹配正整数,包含0。
  • slug,匹配字母、数字以及横杠、下划线组成的字符串。
  • uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
  • path,匹配任何非空字符串,包含了路径分隔符

注册自定义转化器

对于一些复杂或者复用的须要,能够定义本身的转化器。转化器是一个类或接口,它的要求有三点:

  • regex 类属性,字符串类型
  • to_python(self, value) 方法,value是由类属性 regex 所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中。
  • to_url(self, value) 方法,和 to_python 相反,value是一个具体的Python变量值,返回其字符串,一般用于url反向引用。

例子:

class FourDigitYearConverter:  
    regex = '[0-9]{4}'  
    def to_python(self, value):  
        return int(value)  
    def to_url(self, value):  
        return '%04d' % value  

使用register_converter 将其注册到URL配置中:

复制代码
from django.urls import register_converter, path  
from . import converters, views  
register_converter(converters.FourDigitYearConverter, 'yyyy')  
urlpatterns = [  
    path('articles/2003/', views.special_case_2003),  
    path('articles/<yyyy:year>/', views.year_archive),  
    ...  
]  
复制代码

 Django的视图层


视图函数

一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求而且返回Web响应。响应能够是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是任何东西均可以。不管视图自己包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你的Python目录下面。除此以外没有更多的要求了——能够说“没有什么神奇的地方”。为了将代码放在某处,约定是将视图放置在项目或应用程序目录中的名为views.py的文件中。

下面是一个返回当前日期和时间做为HTML文档的视图:

复制代码
from django.shortcuts import render, HttpResponse, HttpResponseRedirect, redirect
import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)
复制代码

让咱们逐行阅读上面的代码:

  • 首先,咱们从 django.shortcuts模块导入了HttpResponse类,以及Python的datetime库。

  • 接着,咱们定义了current_datetime函数。它就是视图函数。每一个视图函数都使用HttpRequest对象做为第一个参数,而且一般称之为request

    注意,视图函数的名称并不重要;不须要用一个统一的命名方式来命名,以便让Django识别它。咱们将其命名为current_datetime,是由于这个名称可以精确地反映出它的功能。

  • 这个视图会返回一个HttpResponse对象,其中包含生成的响应。每一个视图函数都负责返回一个HttpResponse对象。

视图层,熟练掌握两个对象便可:请求对象(request)和响应对象(HttpResponse)

HttpRequest对象

request属性   

django将请求报文中的请求行、首部信息、内容主体封装成 HttpRequest 类中的属性。 除了特殊说明的以外,其余均为只读的。

复制代码
/*

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。

*/
复制代码

request经常使用方法

复制代码
/*

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()
  • render()
  • redirect()

HttpResponse()括号内直接跟一个具体的字符串做为响应体,比较直接很简单,因此这里主要介绍后面两种形式。

render()

1
2
3
render(request, template_name[, context])
 
结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。
参数:
     request: 用于生成响应的请求对象。

     template_name:要使用的模板的完整名称,可选的参数

     context:添加到模板上下文的一个字典。默认是一个空字典。若是字典中的某个值是可调用的,视图将在渲染模板以前调用它。

render方法就是将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面做为响应体。

redirect()

传递要重定向的一个硬编码的URL

1
2
3
def  my_view(request):
     ...
     return  redirect( '/some/url/' )

也能够是一个完整的URL:

1
2
3
def  my_view(request):
     ...
     return  redirect( 'http://example.com/' ) 

key:两次请求 

  关于301与302:

1)301和302的区别。

  301和302状态码都表示重定向,就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,这个地址能够从响应的Location首部中获取
(用户看到的效果就是他输入的地址A瞬间变成了另外一个地址B)——这是它们的共同点。

  他们的不一样在于。301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),搜索引擎在抓取新内容的同时也将旧的网址交换为重定向以后的网址;

  302表示旧地址A的资源还在(仍然能够访问),这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址。 SEO302好于301

 

2)重定向缘由:
(1)网站调整(如改变网页目录结构);
(2)网页被移到一个新地址;
(3)网页扩展名改变(如应用须要把.php改为.Html或.shtml)。
这种状况下,若是不作重定向,则用户收藏夹或搜索引擎数据库中旧地址只能让访问客户获得一个404页面错误信息,访问流量白白丧失;再者某些注册了多个域名的
网站,也须要经过重定向让访问这些域名的用户自动跳转到主站点等。

关于301与302

用redirect能够解释APPEND_SLASH的用法!


 Django的模板层

 

你可能已经注意到咱们在例子视图中返回文本的方式有点特别。 也就是说,HTML被直接硬编码在 Python代码之中。

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

尽管这种技术便于解释视图是如何工做的,但直接将HTML硬编码到你的视图里却并非一个好主意。 让咱们来看一下为何:

  • 对页面设计进行的任何改变都必须对 Python 代码进行相应的修改。 站点设计的修改每每比底层 Python 代码的修改要频繁得多,所以若是能够在不进行 Python 代码修改的状况下变动设计,那将会方便得多。

  • Python 代码编写和 HTML 设计是两项不一样的工做,大多数专业的网站开发环境都将他们分配给不一样的人员(甚至不一样部门)来完成。 设计者和HTML/CSS的编码人员不该该被要求去编辑Python的代码来完成他们的工做。

  • 程序员编写 Python代码和设计人员制做模板两项工做同时进行的效率是最高的,远胜于让一我的等待另外一我的完成对某个既包含 Python又包含 HTML 的文件的编辑工做。

基于这些缘由,将页面的设计和Python的代码分离开会更干净简洁更容易维护。 咱们可使用 Django的 模板系统 (Template System)来实现这种模式,这就是本章要具体讨论的问题。

1
python的模板:HTML代码+模板语法
复制代码
def current_time(req):
    # ================================原始的视图函数
    # import datetime
    # now=datetime.datetime.now()
    # html="<html><body>如今时刻:<h1>%s.</h1></body></html>" %now


    # ================================django模板修改的视图函数
    # from django.template import Template,Context
    # now=datetime.datetime.now()
    # t=Template('<html><body>如今时刻是:<h1>{{current_date}}</h1></body></html>')
    # #t=get_template('current_datetime.html')
    # c=Context({'current_date':str(now)})
    # html=t.render(c)
    #
    # return HttpResponse(html)


    #另外一种写法(推荐)
    import datetime
    now=datetime.datetime.now()
    return render(req, 'current_datetime.html', {'current_date':str(now)[:19]})
复制代码

1 模板语法之变量

在 Django 模板中遍历复杂数据结构的关键是句点字符, 语法:  

1
{{var_name}}

views.py:

复制代码
def index(request):
    import datetime
    s="hello"
    l=[111,222,333]    # 列表
    dic={"name":"yuan","age":18}  # 字典
    date = datetime.date(1993, 5, 2)   # 日期对象
 
    class Person(object):
        def __init__(self,name):
            self.name=name
 
    person_yuan=Person("yuan")  # 自定义类对象
    person_egon=Person("egon")
    person_alex=Person("alex")
 
    person_list=[person_yuan,person_egon,person_alex]
 
 
    return render(request,"index.html",{"l":l,"dic":dic,"date":date,"person_list":person_list}) 
复制代码

template: 

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>

注意:句点符也能够用来引用对象的方法(无参数方法):

1
<h4>字典:{{ dic.name.upper }}< / h4>

2 模板之过滤器

语法:

1
{{obj|filter__name:param}}

default

若是一个变量是false或者为空,使用给定的默认值。不然,使用变量的值。例如:

1
{{ value|default: "nothing"  }}

length

返回值的长度。它对字符串和列表都起做用。例如:

1
{{ value|length }}

若是 value 是 ['a', 'b', 'c', 'd'],那么输出是 4。

filesizeformat

将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB''4.1 MB''102 bytes', 等等)。例如:

1
{{ value|filesizeformat }}

若是 value 是 123456789,输出将会是 117.7 MB。  

date

若是 value=datetime.datetime.now()

1
{{ value|date: "Y-m-d"  }}  

slice

若是 value="hello world"

1
{{ value| slice : "2:-1"  }}

truncatechars

若是字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。

参数:要截断的字符数

例如:

1
{{ value|truncatechars: 9  }}

safe

Django的模板中会对HTML标签和JS等语法标签进行自动转义,缘由显而易见,这样是为了安全。可是有的时候咱们可能不但愿这些HTML元素被转义,好比咱们作一个内容管理系统,后台添加的文章中是通过修饰的,这些修饰多是经过一个相似于FCKeditor编辑加注了HTML修饰符的文本,若是自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,若是是一个单独的变量咱们能够经过过滤器“|safe”的方式告诉Django这段代码是安全的没必要转义。好比:

1
value = "<a href=" ">点击</a>"
1
{{ value|safe}}

这里简单介绍一些经常使用的模板的过滤器,更多详见

3 模板之标签 

标签看起来像是这样的: {% tag %}。标签比变量更加复杂:一些在输出中建立文本,一些经过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。一些标签须要开始和结束标签 (例如{% tag %} ...标签 内容 ... {% endtag %})。

for标签

遍历每个元素:

{% for person in person_list %}
    <p>{{ person.name }}</p>
{% endfor %}

能够利用{% for obj in list reversed %}反向完成循环。

遍历一个字典:

{% for key,val in dic.items %}
    <p>{{ 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

for ... empty

for 标签带有一个可选的{% empty %} 从句,以便在给出的组是空的或者没有被找到时,能够有所操做。

{% for person in person_list %}
    <p>{{ person.name }}</p>

{% empty %}
    <p>sorry,no person here</p>
{% endfor %}

if 标签

{% if %}会对一个变量求值,若是它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。

复制代码
{% if num > 100 or num < 0 %}
    <p>无效</p>
{% elif num > 80 and num < 100 %}
    <p>优秀</p>
{% else %}
    <p>凑活吧</p>
{% endif %}
复制代码

with

使用一个简单地名字缓存一个复杂的变量,当你须要使用一个“昂贵的”方法(好比访问数据库)不少次的时候是很是有用的

例如:

{% with total=business.employees.count %}
    {{ total }} employee{{ total|pluralize }}
{% endwith %}

csrf_token

这个标签用于跨站请求伪造保护

4 自定义标签和过滤器

一、在settings中的INSTALLED_APPS配置当前app,否则django没法找到自定义的simple_tag.

二、在app中建立templatetags模块(模块名只能是templatetags)

三、建立任意 .py 文件,如:my_tags.py

四、在使用自定义simple_tag和filter的html文件中导入以前建立的 my_tags.py

1
{ %  load my_tags  % } 

五、使用simple_tag和filter(如何调用)

1
2
3
4
5
6
7
8
9
10
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .html
{ %  load xxx  % }  
      
# num=12
{{ num|filter_multi: 2  }}  #24
 
{{ num|filter_multi: "[22,333,4444]"  }}
 
{ %  simple_tag_multi  2  5  % }  参数不限,但不能放在 if  for 语句中
{ %  simple_tag_multi num  5  % }

注意:filter能够用在if等语句后,simple_tag不能够

5 模板继承 (extend)

Django模版引擎中最强大也是最复杂的部分就是模版继承了。模版继承可让您建立一个基本的“骨架”模版,它包含您站点中的所有元素,而且能够定义可以被子模版覆盖的 blocks 。

经过从下面这个例子开始,能够容易的理解模版继承:

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}My amazing site{%/span> endblock %}</title>
</head>

<body>
    <div id="sidebar">
        {% block sidebar %}
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
        </ul>
        {% endblock %}
    </div>

    <div id="content">
        {% block content %}{% endblock %}
    </div>
</body>
</html>
复制代码

这个模版,咱们把它叫做 base.html, 它定义了一个能够用于两列排版页面的简单HTML骨架。“子模版”的工做是用它们的内容填充空的blocks。

在这个例子中, block 标签订义了三个能够被子模版内容填充的block。 block 告诉模版引擎: 子模版可能会覆盖掉模版中的这些位置。

子模版可能看起来是这样的:

extends 标签是这里的关键。它告诉模版引擎,这个模版“继承”了另外一个模版。当模版系统处理这个模版时,首先,它将定位父模版——在此例中,就是“base.html”。

那时,模版引擎将注意到 base.html 中的三个 block 标签,并用子模版中的内容来替换这些block。根据 blog_entries 的值,输出可能看起来是这样的:

请注意,子模版并无定义 sidebar block,因此系统使用了父模版中的值。父模版的 {% block %} 标签中的内容老是被用做备选内容(fallback)。

这种方式使代码获得最大程度的复用,而且使得添加内容到共享的内容区域更加简单,例如,部分范围内的导航。

这里是使用继承的一些提示:

  • 若是你在模版中使用 {% extends %} 标签,它必须是模版中的第一个标签。其余的任何状况下,模版继承都将没法工做。

  • 在base模版中设置越多的 {% block %} 标签越好。请记住,子模版没必要定义所有父模版中的blocks,因此,你能够在大多数blocks中填充合理的默认内容,而后,只定义你须要的那一个。多一点钩子总比少一点好。

  • 若是你发现你本身在大量的模版中复制内容,那可能意味着你应该把内容移动到父模版中的一个 {% block %} 中。

  • If you need to get the content of the block from the parent template, the {{ block.super }} variable will do the trick. This is useful if you want to add to the contents of a parent block instead of completely overriding it. Data inserted using {{ block.super }} will not be automatically escaped (see the next section), since it was already escaped, if necessary, in the parent template.

  • 为了更好的可读性,你也能够给你的 {% endblock %} 标签一个 名字 。例如:

    1
    2
    3
    { %  block content  % }
    ...
    { %  endblock content  % }  

    在大型模版中,这个方法帮你清楚的看到哪个  {% block %} 标签被关闭了。

  • 不能在一个模版中定义多个相同名字的 block 标签。
相关文章
相关标签/搜索