日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

中國最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2

django教程

Django 模版進階

閱讀 (2268)

在前一章中,你可能已經注意到我們在例子視圖中返回文本的方式有點特別。 也就是說,HTML被直接硬編碼在 Python 代碼之中。

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

盡管這種技術便于解釋視圖是如何工作的,但直接將HTML硬編碼到你的視圖里卻并不是一個好主意。 讓我們來看一下為什么:

  • 對頁面設計進行的任何改變都必須對 Python 代碼進行相應的修改。 站點設計的修改往往比底層 Python 代碼的修改要頻繁得多,因此如果可以在不進行 Python 代碼修改的情況下變更設計,那將會方便得多。

  • Python 代碼編寫和 HTML 設計是兩項不同的工作,大多數專業的網站開發環境都將他們分配給不同的人員(甚至不同部門)來完成。 設計者和HTML/CSS的編碼人員不應該被要求去編輯Python的代碼來完成他們的工作。

  • 程序員編寫 Python代碼和設計人員制作模板兩項工作同時進行的效率是最高的,遠勝于讓一個人等待另一個人完成對某個既包含 Python又包含 HTML 的文件的編輯工作。

基于這些原因,將頁面的設計和Python的代碼分離開會更干凈簡潔更容易維護。 我們可以使用 Django的 模板系統 (Template System)來實現這種模式,這就是本章要具體討論的問題。

模板系統基本知識

模板是一個文本,用于分離文檔的表現形式和內容。 模板定義了占位符以及各種用于規范文檔該如何顯示的各部分基本邏輯(模板標簽)。 模板通常用于產生HTML,但是Django的模板也能產生任何基于文本格式的文檔。

讓我們從一個簡單的例子模板開始。 該模板描述了一個向某個與公司簽單人員致謝 HTML 頁面。 可將其視為一個格式信函:

<html>
<head><title>Ordering noticetitle>head>

<body>

<h1>Ordering noticeh1>

<p>Dear {{ person_name }},p>

<p>Thanks for placing an order from {{ company }}. It's scheduled to
ship on {{ ship_date|date:"F j, Y" }}.p>

<p>Here are the items you've ordered:p>

<ul>
{% for item in item_list %}
    <li>{{ item }}li>
{% endfor %}
ul>

{% if ordered_warranty %}
    <p>Your warranty information will be included in the packaging.p>
{% else %}
    <p>You didn't order a warranty, so you're on your own when
    the products inevitably stop working.p>
{% endif %}

<p>Sincerely,<br />{{ company }}p>

body>
html>

該模板是一段添加了些許變量和模板標簽的基礎 HTML 。 讓我們逐步分析一下:

用兩個大括號括起來的文字(例如 {{ person_name }} )稱為 變量(variable) 。這意味著在此處插入指定變量的值。 如何指定變量的值呢? 稍后就會說明。

被大括號和百分號包圍的文本(例如 {% if ordered_warranty %} )是 模板標簽(template tag) 。標簽(tag)定義比較明確,即: 僅通知模板系統完成某些工作的標簽。

這個例子中的模板包含一個for標簽( {% for item in item_list %} )和一個if 標簽({% if ordered_warranty %} )

for標簽類似Python的for語句,可讓你循環訪問序列里的每一個項目。 if 標簽,正如你所料,是用來執行邏輯判斷的。 在這里,tag標簽檢查ordered_warranty值是否為True。如果是,模板系統將顯示{% if ordered_warranty %}和{% else %}之間的內容;否則將顯示{% else %}和{% endif %}之間的內容。{% else %}是可選的。

最后,這個模板的第二段中有一個關于_filter_過濾器的例子,它是一種最便捷的轉換變量輸出格式的方式。 如這個例子中的{{ship_date|date:”F j, Y” }},我們將變量ship_date傳遞給date過濾器,同時指定參數”F j,Y”。date過濾器根據參數進行格式輸出。 過濾器是用管道符(|)來調用的,具體可以參見Unix管道符。

Django 模板含有很多內置的tags和filters,我們將陸續進行學習. 附錄F列出了很多的tags和filters的列表,熟悉這些列表對你來說是個好建議. 你依然可以利用它創建自己的tag和filters。這些我們在第9章會講到。

如何使用模板系統

讓我們深入研究模板系統,你將會明白它是如何工作的。但我們暫不打算將它與先前創建的視圖結合在一起,因為我們現在的目的是了解它是如何獨立工作的。 。 (換言之, 通常你會將模板和視圖一起使用,但是我們只是想突出模板系統是一個Python庫,你可以在任何地方使用它,而不僅僅是在Django視圖中。)

在Python代碼中使用Django模板的最基本方式如下:

  1. 可以用原始的模板代碼字符串創建一個 Template 對象, Django同樣支持用指定模板文件路徑的方式來創建 Template 對象;

  2. 調用模板對象的render方法,并且傳入一套變量context。它將返回一個基于模板的展現字符串,模板中的變量和標簽會被context值替換。

代碼如下:

>>> from django import template
>>> t = template.Template('My name is {{ name }}.')
>>> c = template.Context({'name': 'Adrian'})
>>> print t.render(c)
My name is Adrian.
>>> c = template.Context({'name': 'Fred'})
>>> print t.render(c)
My name is Fred.

以下部分逐步的詳細介紹

創建模板對象

創建一個 Template 對象最簡單的方法就是直接實例化它。 Template 類就在 django.template 模塊中,構造函數接受一個參數,原始模板代碼。 讓我們深入挖掘一下 Python的解釋器看看它是怎么工作的。

轉到project目錄(在第二章由 django-admin.py startproject 命令創建), 輸入命令python manage.py shell 啟動交互界面。

一個特殊的Python提示符

如果你曾經使用過Python,你一定好奇,為什么我們運行python manage.py shell而不是python。這兩個命令都會啟動交互解釋器,但是manage.py shell命令有一個重要的不同: 在啟動解釋器之前,它告訴Django使用哪個設置文件。 Django框架的大部分子系統,包括模板系統,都依賴于配置文件;如果Django不知道使用哪個配置文件,這些系統將不能工作。

如果你想知道,這里將向你解釋它背后是如何工作的。 Django搜索DJANGO_SETTINGS_MODULE環境變量,它被設置在settings.py中。例如,假設mysite在你的Python搜索路徑中,那么DJANGO_SETTINGS_MODULE應該被設置為:’mysite.settings’。

當你運行命令:python manage.py shell,它將自動幫你處理DJANGO_SETTINGS_MODULE。 在當前的這些示例中,我們鼓勵你使用python manage.py shell這個方法,這樣可以免去你大費周章地去配置那些你不熟悉的環境變量。

隨著你越來越熟悉Django,你可能會偏向于廢棄使用manage.py shell ,而是在你的配置文件.bash_profile中手動添加 DJANGO_SETTINGS_MODULE這個環境變量。

讓我們來了解一些模板系統的基本知識:

>>> from django.template import Template
>>> t = Template('My name is {{ name }}.')
>>> print t

如果你跟我們一起做,你將會看到下面的內容:

0xb7d5f24c 每次都會不一樣,這沒什么關系;這只是Python運行時 Template 對象的ID。

當你創建一個 Template 對象,模板系統在內部編譯這個模板到內部格式,并做優化,做好 渲染的準備。 如果你的模板語法有錯誤,那么在調用 Template() 時就會拋出 TemplateSyntaxError 異常:

>>> from django.template import Template
>>> t = Template('{% notatag %}')
Traceback (most recent call last):
  File "", line 1, in ?
  ...
django.template.TemplateSyntaxError: Invalid block tag: 'notatag'

這里,塊標簽(block tag)指向的是{% notatag %},塊標簽與模板標簽是同義的。

系統會在下面的情形拋出 TemplateSyntaxError 異常:

  • 無效的tags

  • 標簽的參數無效

  • 無效的過濾器

  • 過濾器的參數無效

  • 無效的模板語法

  • 未封閉的塊標簽 (針對需要封閉的塊標簽)

模板渲染

一旦你創建一個 Template 對象,你可以用 context 來傳遞數據給它。 一個context是一系列變量和它們值的集合。

context在Django里表現為 Context 類,在 django.template 模塊里。 她的構造函數帶有一個可選的參數: 一個字典映射變量和它們的值。 調用 Template 對象 的 render() 方法并傳遞context來填充模板:

>>> from django.template import Context, Template
>>> t = Template('My name is {{ name }}.')
>>> c = Context({'name': 'Stephane'})
>>> t.render(c)
u'My name is Stephane.'

我們必須指出的一點是,t.render(c)返回的值是一個Unicode對象,不是普通的Python字符串。 你可以通過字符串前的u來區分。 在框架中,Django會一直使用Unicode對象而不是普通的字符串。 如果你明白這樣做給你帶來了多大便利的話,盡可能地感激Django在幕后有條不紊地為你所做這這么多工作吧。 如果不明白你從中獲益了什么,別擔心。你只需要知道Django對Unicode的支持,將讓你的應用程序輕松地處理各式各樣的字符集,而不僅僅是基本的A-Z英文字符。

字典和Contexts

Python的字典數據類型就是關鍵字和它們值的一個映射。 Context 和字典很類似, Context 還提供更多的功能,請看第九章。

變量名必須由英文字符開始 (A-Z或a-z)并可以包含數字字符、下劃線和小數點。 (小數點在這里有特別的用途,稍后我們會講到)變量是大小寫敏感的。

下面是編寫模板并渲染的示例:

>>> from django.template import Template, Context
>>> raw_template = """

Dear {{ person_name }},

... ...

Thanks for placing an order from {{ company }}. It's scheduled to ... ship on {{ ship_date|date:"F j, Y" }}.

... ... {% if ordered_warranty %} ...

Your warranty information will be included in the packaging.

... {% else %} ...

You didn't order a warranty, so you're on your own when ... the products inevitably stop working.

... {% endif %} ... ...

Sincerely,
{{ company }}

"""
>>> t = Template(raw_template) >>> import datetime >>> c = Context({'person_name': 'John Smith', ... 'company': 'Outdoor Equipment', ... 'ship_date': datetime.date(2009, 4, 2), ... 'ordered_warranty': False}) >>> t.render(c) u"

Dear John Smith,

\n\n

Thanks for placing an order from Outdoor Equipment. It's scheduled to\nship on April 2, 2009.

\n\n\n

You didn't order a warranty, so you're on your own when\nthe products inevitably stop working.

\n\n\n

Sincerely,
Outdoor Equipment

"

讓我們逐步來分析下這段代碼:

首先我們導入 (import)類 Template 和 Context ,它們都在模塊 django.template 里。

我們把模板原始文本保存到變量 raw_template 。注意到我們使用了三個引號來 標識這些文本,因為這樣可以包含多行。

接下來,我們創建了一個模板對象 t ,把 raw_template 作為 Template 類構造函數的參數。

我們從Python的標準庫導入 datetime 模塊,以后我們將會使用它。

然后,我們創建一個 Context 對象, c 。 Context 構造的參數是Python 字典數據類型。 在這里,我們指定參數 person_name 的值是 'John Smith' , 參數company 的值為 ‘Outdoor Equipment’ ,等等。

最后,我們在模板對象上調用 render() 方法,傳遞 context參數給它。 這是返回渲染后的模板的方法,它會替換模板變量為真實的值和執行塊標簽。

注意,warranty paragraph顯示是因為 ordered_warranty 的值為 True . 注意時間的顯示, April 2, 2009, 它是按 'F j, Y' 格式顯示的。

如果你是Python初學者,你可能在想為什么輸出里有回車換行的字符('\n' )而不是 顯示回車換行? 因為這是Python交互解釋器的緣故: 調用 t.render(c) 返回字符串, 解釋器缺省顯示這些字符串的 真實內容呈現 ,而不是打印這個變量的值。 要顯示換行而不是 '\n' ,使用 print 語句: print t.render(c) 。

這就是使用Django模板系統的基本規則: 寫模板,創建 Template 對象,創建 Context , 調用 render() 方法。

同一模板,多個上下文

一旦有了 模板 對象,你就可以通過它渲染多個context, 例如:

>>> from django.template import Template, Context
>>> t = Template('Hello, {{ name }}')
>>> print t.render(Context({'name': 'John'}))
Hello, John
>>> print t.render(Context({'name': 'Julie'}))
Hello, Julie
>>> print t.render(Context({'name': 'Pat'}))
Hello, Pat

無論何時我們都可以像這樣使用同一模板源渲染多個context,只進行 一次模板創建然后多次調用render()方法渲染會更為高效:

# Bad
for name in ('John', 'Julie', 'Pat'):
    t = Template('Hello, {{ name }}')
    print t.render(Context({'name': name}))

# Good
t = Template('Hello, {{ name }}')
for name in ('John', 'Julie', 'Pat'):
    print t.render(Context({'name': name}))

Django 模板解析非??旖?。 大部分的解析工作都是在后臺通過對簡短正則表達式一次性調用來完成。 這和基于 XML 的模板引擎形成鮮明對比,那些引擎承擔了 XML 解析器的開銷,且往往比 Django 模板渲染引擎要慢上幾個數量級。

深度變量的查找

在到目前為止的例子中,我們通過 context 傳遞的簡單參數值主要是字符串,還有一個 datetime.date 范例。 然而,模板系統能夠非常簡潔地處理更加復雜的數據結構,例如list、dictionary和自定義的對象。

在 Django 模板中遍歷復雜數據結構的關鍵是句點字符 (.)。

最好是用幾個例子來說明一下。 比如,假設你要向模板傳遞一個 Python 字典。 要通過字典鍵訪問該字典的值,可使用一個句點:

>>> from django.template import Template, Context
>>> person = {'name': 'Sally', 'age': '43'}
>>> t = Template('{{ person.name }} is {{ person.age }} years old.')
>>> c = Context({'person': person})
>>> t.render(c)
u'Sally is 43 years old.'

同樣,也可以通過句點來訪問對象的屬性。 比方說, Python 的 datetime.date 對象有 year 、 month 和 day幾個屬性,你同樣可以在模板中使用句點來訪問這些屬性:

>>> from django.template import Template, Context
>>> import datetime
>>> d = datetime.date(1993, 5, 2)
>>> d.year
1993
>>> d.month
5
>>> d.day
2
>>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.')
>>> c = Context({'date': d})
>>> t.render(c)
u'The month is 5 and the year is 1993.'

這個例子使用了一個自定義的類,演示了通過實例變量加一點(dots)來訪問它的屬性,這個方法適用于任意的對象。

>>> from django.template import Template, Context
>>> class Person(object):
...     def __init__(self, first_name, last_name):
...         self.first_name, self.last_name = first_name, last_name
>>> t = Template('Hello, {{ person.first_name }} {{ person.last_name }}.')
>>> c = Context({'person': Person('John', 'Smith')})
>>> t.render(c)
u'Hello, John Smith.'

點語法也可以用來引用對象的 方法。 例如,每個 Python 字符串都有 upper() 和 isdigit() 方法,你在模板中可以使用同樣的句點語法來調用它們:

>>> from django.template import Template, Context
>>> t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}')
>>> t.render(Context({'var': 'hello'}))
u'hello -- HELLO -- False'
>>> t.render(Context({'var': '123'}))
u'123 -- 123 -- True'

注意這里調用方法時并 沒有 使用圓括號 而且也無法給該方法傳遞參數;你只能調用不需參數的方法。 (我們將在本章稍后部分解釋該設計觀。)

最后,句點也可用于訪問列表索引,例如:

>>> from django.template import Template, Context
>>> t = Template('Item 2 is {{ items.2 }}.')
>>> c = Context({'items': ['apples', 'bananas', 'carrots']})
>>> t.render(c)
u'Item 2 is carrots.'

不允許使用負數列表索引。 像 {{ items.-1 }} 這樣的模板變量將會引發TemplateSyntaxError

Python 列表類型

一點提示: Python的列表是從0開始索引。 第一項的索引是0,第二項的是1,依此類推。

句點查找規則可概括為: 當模板系統在變量名中遇到點時,按照以下順序嘗試進行查找:

  • 字典類型查找 (比如 foo["bar"] )

  • 屬性查找 (比如 foo.bar )

  • 方法調用 (比如 foo.bar() )

  • 列表類型索引查找 (比如 foo[bar] )

系統使用找到的第一個有效類型。 這是一種短路邏輯。

句點查找可以多級深度嵌套。 例如在下面這個例子中 {{person.name.upper}} 會轉換成字典類型查找(person['name'] ) 然后是方法調用( upper() ):

>>> from django.template import Template, Context
>>> person = {'name': 'Sally', 'age': '43'}
>>> t = Template('{{ person.name.upper }} is {{ person.age }} years old.')
>>> c = Context({'person': person})
>>> t.render(c)
u'SALLY is 43 years old.'

方法調用行為

方法調用比其他類型的查找略為復雜一點。 以下是一些注意事項:

在方法查找過程中,如果某方法拋出一個異常,除非該異常有一個 silent_variable_failure 屬性并且值為 True ,否則的話它將被傳播。如果異常被傳播,模板里的指定變量會被置為空字符串,比如:

>>> t = Template("My name is {{ person.first_name }}.")
>>> class PersonClass3:
...     def first_name(self):
...         raise AssertionError, "foo"
>>> p = PersonClass3()
>>> t.render(Context({"person": p}))
Traceback (most recent call last):
...
AssertionError: foo

>>> class SilentAssertionError(AssertionError):
...     silent_variable_failure = True
>>> class PersonClass4:
...     def first_name(self):
...         raise SilentAssertionError
>>> p = PersonClass4()
>>> t.render(Context({"person": p}))
u'My name is .'

僅在方法無需傳入參數時,其調用才有效。 否則,系統將會轉移到下一個查找類型(列表索引查找)。

顯然,有些方法是有副作用的,好的情況下允許模板系統訪問它們可能只是干件蠢事,壞的情況下甚至會引發安全漏洞。

例如,你的一個 BankAccount 對象有一個 delete() 方法。 如果某個模板中包含了像{{ account.delete }}這樣的標簽,其中account 又是BankAccount 的一個實例,請注意在這個模板載入時,account對象將被刪除。

要防止這樣的事情發生,必須設置該方法的 alters_data 函數屬性:

def delete(self):
    # Delete the account
delete.alters_data = True

模板系統不會執行任何以該方式進行標記的方法。 接上面的例子,如果模板文件里包含了{{ account.delete }} ,對象又具有 delete()方法,而且delete() 有alters_data=True這個屬性,那么在模板載入時, delete()方法將不會被執行。 它將靜靜地錯誤退出。

如何處理無效變量

默認情況下,如果一個變量不存在,模板系統會把它展示為空字符串,不做任何事情來表示失敗。 例如:

>>> from django.template import Template, Context
>>> t = Template('Your name is {{ name }}.')
>>> t.render(Context())
u'Your name is .'
>>> t.render(Context({'var': 'hello'}))
u'Your name is .'
>>> t.render(Context({'NAME': 'hello'}))
u'Your name is .'
>>> t.render(Context({'Name': 'hello'}))
u'Your name is .'

系統靜悄悄地表示失敗,而不是引發一個異常,因為這通常是人為錯誤造成的。 這種情況下,因為變量名有錯誤的狀況或名稱, 所有的查詢都會失敗。 現實世界中,對于一個web站點來說,如果僅僅因為一個小的模板語法錯誤而造成無法訪問,這是不可接受的。

玩一玩上下文(context)對象

多數時間,你可以通過傳遞一個完全填充(full populated)的字典給 Context() 來初始化 上下文(Context) 。 但是初始化以后,你也可以使用標準的Python字典語法(syntax)向上下文(Context) 對象添加或者刪除條目:

>>> from django.template import Context
>>> c = Context({"foo": "bar"})
>>> c['foo']
'bar'
>>> del c['foo']
>>> c['foo']
Traceback (most recent call last):
  ...
KeyError: 'foo'
>>> c['newvariable'] = 'hello'
>>> c['newvariable']
'hello'

基本的模板標簽和過濾器

像我們以前提到過的,模板系統帶有內置的標簽和過濾器。 下面的章節提供了一個多數通用標簽和過濾器的簡要說明。

標簽

if/else

{% if %} 標簽檢查(evaluate)一個變量,如果這個變量為真(即,變量存在,非空,不是布爾值假),系統會顯示在 {% if %} 和 {% endif %} 之間的任何內容,例如:

{% if today_is_weekend %}
    

Welcome to the weekend!p> {% endif %}

{% else %} 標簽是可選的:

{% if today_is_weekend %}
    <p>Welcome to the weekend!p>
{% else %}
    <p>Get back to work.p>
{% endif %}

Python 的“真值”

在Python和Django模板系統中,以下這些對象相當于布爾值的False

  • 空列表([] )

  • 空元組(() )

  • 空字典({} )

  • 空字符串('' )

  • 零值(0 )

  • 特殊對象None

  • 對象False(很明顯)

  • 提示:你也可以在自定義的對象里定義他們的布爾值屬性(這個是python的高級用法)。

除以上幾點以外的所有東西都視為True

{% if %} 標簽接受 and , or 或者 not 關鍵字來對多個變量做判斷 ,或者對變量取反( not ),例如: 例如:

{% if athlete_list and coach_list %}
    Both athletes and coaches are available.
{% endif %}

{% if not athlete_list %}
    There are no athletes.
{% endif %}

{% if athlete_list or coach_list %}
    There are some athletes or some coaches.
{% endif %}

{% if not athlete_list or coach_list %}
    There are no athletes or there are some coaches.
{% endif %}

{% if athlete_list and not coach_list %}
    There are some athletes and absolutely no coaches.
{% endif %}

{% if %} 標簽不允許在同一個標簽中同時使用 and 和 or ,因為邏輯上可能模糊的,例如,如下示例是錯誤的: 比如這樣的代碼是不合法的:

{% if athlete_list and coach_list or cheerleader_list %}

系統不支持用圓括號來組合比較操作。 如果你確實需要用到圓括號來組合表達你的邏輯式,考慮將它移到模板之外處理,然后以模板變量的形式傳入結果吧。 或者,僅僅用嵌套的{% if %}標簽替換吧,就像這樣:

{% if athlete_list %}
    {% if coach_list or cheerleader_list %}
        We have athletes, and either coaches or cheerleaders!
    {% endif %}
{% endif %}

多次使用同一個邏輯操作符是沒有問題的,但是我們不能把不同的操作符組合起來。 例如,這是合法的:

{% if athlete_list or coach_list or parent_list or teacher_list %}

并沒有 {% elif %} 標簽, 請使用嵌套的{% if %} 標簽來達成同樣的效果:

{% if athlete_list %}
    Here are the athletes: {{ athlete_list }}.
{% else %}
    No athletes are available.
    {% if coach_list %}
        Here are the coaches: {{ coach_list }}.
    {% endif %}
{% endif %}

一定要用 {% endif %} 關閉每一個 {% if %} 標簽。

for

{% for %} 允許我們在一個序列上迭代。 與Python的 for 語句的情形類似,循環語法是 for X in Y ,Y是要迭代的序列而X是在每一個特定的循環中使用的變量名稱。 每一次循環中,模板系統會渲染在 {% for %} 和{% endfor %} 之間的所有內容。

例如,給定一個運動員列表 athlete_list 變量,我們可以使用下面的代碼來顯示這個列表:

<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}li>
{% endfor %}
ul>

給標簽增加一個 reversed 使得該列表被反向迭代:

{% for athlete in athlete_list reversed %}
...
{% endfor %}

可以嵌套使用 {% for %} 標簽:

{% for athlete in athlete_list %}
    <h1>{{ athlete.name }}h1>
    <ul>
    {% for sport in athlete.sports_played %}
        <li>{{ sport }}li>
    {% endfor %}
    ul>
{% endfor %}

在執行循環之前先檢測列表的大小是一個通常的做法,當列表為空時輸出一些特別的提示。

{% if athlete_list %}
    {% for athlete in athlete_list %}
        

{{ athlete.name }}

{% endfor %} {% else %}

There are no athletes. Only computer programmers.

{% endif %}

因為這種做法十分常見,所以for 標簽支持一個可選的{% empty %} 分句,通過它我們可以定義當列表為空時的輸出內容 下面的例子與之前那個等價:

{% for athlete in athlete_list %}
    <p>{{ athlete.name }}p>
{% empty %}
    <p>There are no athletes. Only computer programmers.p>
{% endfor %}

Django不支持退出循環操作。 如果我們想退出循環,可以改變正在迭代的變量,讓其僅僅包含需要迭代的項目。 同理,Django也不支持continue語句,我們無法讓當前迭代操作跳回到循環頭部。 (請參看本章稍后的理念和限制小節,了解下決定這個設計的背后原因)

在每個{% for %}循環里有一個稱為forloop 的模板變量。這個變量有一些提示循環進度信息的屬性。

forloop.counter 總是一個表示當前循環的執行次數的整數計數器。 這個計數器是從1開始的,所以在第一次循環時 forloop.counter 將會被設置為1。

{% for item in todo_list %}
    <p>{{ forloop.counter }}: {{ item }}p>
{% endfor %}

forloop.counter0 類似于 forloop.counter ,但是它是從0計數的。 第一次執行循環時這個變量會被設置為0。

forloop.revcounter 是表示循環中剩余項的整型變量。 在循環初次執行時 forloop.revcounter 將被設置為序列中項的總數。 最后一次循環執行中,這個變量將被置1。

forloop.revcounter0 類似于 forloop.revcounter ,但它以0做為結束索引。 在第一次執行循環時,該變量會被置為序列的項的個數減1。

forloop.first 是一個布爾值,如果該迭代是第一次執行,那么它被置為```` 在下面的情形中這個變量是很有用的:

System Message: WARNING/2 (, line 1071); backlink

Inline literal start-string without end-string.

{% for object in objects %}
{% if forloop.first %}
  • class="first">{% else %}
  • {% endif %} {{ object }}
  • {% endfor %}r %}

    forloop.last 是一個布爾值;在最后一次執行循環時被置為True。 一個常見的用法是在一系列的鏈接之間放置管道符(|)

    {% for link in links %}{{ link }}{% if not forloop.last %} | {% endif %}{% endfor %}

    上面的模板可能會產生如下的結果:

    Link1 | Link2 | Link3 | Link4

    另一個常見的用途是為列表的每個單詞的加上逗號。

    Favorite places:
    {% for p in places %}{{ p }}{% if not forloop.last %}, {% endif %}{% endfor %}

    forloop.parentloop 是一個指向當前循環的上一級循環的 forloop 對象的引用(在嵌套循環的情況下)。 例子在此:

    {% for country in countries %}
        <table>
        {% for city in country.city_list %}
            <tr>
            <td>Country #{{ forloop.parentloop.counter }}td>
            <td>City #{{ forloop.counter }}td>
            <td>{{ city }}td>
            tr>
        {% endfor %}
        table>
    {% endfor %}

    forloop 變量僅僅能夠在循環中使用。 在模板解析器碰到{% endfor %}標簽后,forloop就不可訪問了。

    Context和forloop變量

    在一個 {% for %} 塊中,已存在的變量會被移除,以避免 forloop 變量被覆蓋。 Django會把這個變量移動到forloop.parentloop 中。通常我們不用擔心這個問題,但是一旦我們在模板中定義了 forloop 這個變量(當然我們反對這樣做),在 {% for %} 塊中它會在 forloop.parentloop 被重新命名。

    ifequal/ifnotequal

    Django模板系統壓根兒就沒想過實現一個全功能的編程語言,所以它不允許我們在模板中執行Python的語句(還是那句話,要了解更多請參看理念和限制小節)。 但是比較兩個變量的值并且顯示一些結果實在是個太常見的需求了,所以Django提供了 {% ifequal %} 標簽供我們使用。

    {% ifequal %} 標簽比較兩個值,當他們相等時,顯示在 {% ifequal %} 和 {% endifequal %} 之中所有的值。

    下面的例子比較兩個模板變量 user 和 currentuser :

    {% ifequal user currentuser %}
        

    Welcome!h1> {% endifequal %}

    參數可以是硬編碼的字符串,隨便用單引號或者雙引號引起來,所以下列代碼都是正確的:

    {% ifequal section 'sitenews' %}
        <h1>Site Newsh1>
    {% endifequal %}
    
    {% ifequal section "community" %}
        <h1>Communityh1>
    {% endifequal %}

    和 {% if %} 類似, {% ifequal %} 支持可選的 {% else%} 標簽:

    {% ifequal section 'sitenews' %}
        <h1>Site Newsh1>
    {% else %}
        <h1>No News Hereh1>
    {% endifequal %}

    只有模板變量,字符串,整數和小數可以作為 {% ifequal %} 標簽的參數。下面是合法參數的例子:

    {% ifequal variable 1 %}
    {% ifequal variable 1.23 %}
    {% ifequal variable 'foo' %}
    {% ifequal variable "foo" %}

    其他任何類型,例如Python的字典類型、列表類型、布爾類型,不能用在 {% ifequal %} 中。 下面是些錯誤的例子:

    {% ifequal variable True %}
    {% ifequal variable [1, 2, 3] %}
    {% ifequal variable {'key': 'value'} %}

    如果你需要判斷變量是真還是假,請使用 {% if %} 來替代 {% ifequal %} 。

    注釋

    就像HTML或者Python,Django模板語言同樣提供代碼注釋。 注釋使用 {# #} :

    {# This is a comment #}

    注釋的內容不會在模板渲染時輸出。

    用這種語法的注釋不能跨越多行。 這個限制是為了提高模板解析的性能。 在下面這個模板中,輸出結果和模板本身是 完全一樣的(也就是說,注釋標簽并沒有被解析為注釋):

    This is a {# this is not
    a comment #}
    test.

    如果要實現多行注釋,可以使用{% comment %} 模板標簽,就像這樣:

    {% comment %}
    This is a
    multi-line comment.
    {% endcomment %}

    過濾器

    就象本章前面提到的一樣,模板過濾器是在變量被顯示前修改它的值的一個簡單方法。 過濾器使用管道字符,如下所示:

    {{ name|lower }}

    顯示的內容是變量 {{ name }} 被過濾器 lower 處理后的結果,它功能是轉換文本為小寫。

    過濾管道可以被 套接 ,既是說,一個過濾器管道的輸出又可以作為下一個管道的輸入,如此下去。 下面的例子實現查找列表的第一個元素并將其轉化為大寫。

    {{ my_list|first|upper }}

    有些過濾器有參數。 過濾器的參數跟隨冒號之后并且總是以雙引號包含。 例如:

    {{ bio|truncatewords:"30" }}

    這個將顯示變量 bio 的前30個詞。

    以下幾個是最為重要的過濾器的一部分。 附錄F包含其余的過濾器。

    addslashes : 添加反斜杠到任何反斜杠、單引號或者雙引號前面。 這在處理包含JavaScript的文本時是非常有用的。

    date : 按指定的格式字符串參數格式化 date 或者 datetime 對象, 范例:

    {{ pub_date|date:"F j, Y" }}

    格式參數的定義在附錄F中。

    length : 返回變量的長度。 對于列表,這個參數將返回列表元素的個數。 對于字符串,這個參數將返回字符串中字符的個數。 你可以對列表或者字符串,或者任何知道怎么測定長度的Python 對象使用這個方法(也就是說,有 len() 方法的對象)。

    理念與局限

    現在你已經對Django的模板語言有一些認識了,我們將指出一些特意設置的限制和為什么要這樣做 背后的一些設計哲學。

    相對與其他的網絡應用的組件,模板的語法很具主觀性,因此可供程序員的選擇方案也很廣泛。 事實上,Python有成十上百的 開放源碼的模板語言實現。 每個實現都是因為開發者認為現存的模板語言不夠用。 (事實上,對一個 Python開發者來說,寫一個自己的模板語言就象是某種“成人禮”一樣! 如果你還沒有完成一個自己的 模板語言,好好考慮寫一個,這是一個非常有趣的鍛煉。 )

    明白了這個,你也許有興趣知道事實上Django并不強制要求你必須使用它的模板語言。 因為Django 雖然被設計成一個FULL-Stack的Web框架,它提供了開發者所必需的所有組件,而且在大多數情況 使用Django模板系統會比其他的Python模板庫要 更方便 一點,但是并不是嚴格要求你必須使用 它。 你將在后續的“視圖中應用模板”這一章節中看到,你還可以非常容易地在Django中使用其他的模板語言。

    雖然如此,很明顯,我們對Django模板語言的工作方式有著強烈的偏愛。 這個模板語言來源于World Online的開發經驗和Django創造者們集體智慧的結晶。 下面是關于它的一些設計哲學理念:

    業務邏輯應該和表現邏輯相對分開 。我們將模板系統視為控制表現及表現相關邏輯的工具,僅此而已。 模板系統不應提供超出此基本目標的功能。

    出于這個原因,在 Django 模板中是不可能直接調用 Python 代碼的。 所有的編程工作基本上都被局限于模板標簽的能力范圍。 當然, 有可能寫出自定義的模板標簽來完成任意工作,但這些“超范圍”的 Django 模板標簽有意地不允許執行任何 Python 代碼。

    語法不應受到 HTML/XML 的束縛 。盡管 Django 模板系統主要用于生成 HTML,它還是被有意地設計為可生成非 HTML 格式,如純文本。 一些其它的模板語言是基于 XML 的,將所有的模板邏輯置于 XML 標簽與屬性之中,而 Django 有意地避開了這種限制。 強制要求使用有效 XML 編寫模板將會引發大量的人為錯誤和難以理解的錯誤信息,而且使用 XML 引擎解析模板也會導致令人無法容忍的模板處理開銷。

    假定設計師精通 HTML 編碼 。模板系統的設計意圖并不是為了讓模板一定能夠很好地顯示在 Dreamweaver 這樣的所見即所得編輯器中。 這種限制過于苛刻,而且會使得語法不能像目前這樣的完美。 Django 要求模板創作人員對直接編輯 HTML 非常熟悉。

    假定設計師不是 Python 程序員 。模板系統開發人員認為:模板通常由設計師而非程序員來編寫,因此不應被假定擁有Python開發知識。

    當然,系統同樣也特意地提供了對那些 Python 程序員進行模板制作的小型團隊的支持。 它提供了一種工作模式,允許通過編寫原生 Python 代碼進行系統語法拓展。 (詳見第十章)

    目標并不是要發明一種編程語言 。目標是恰到好處地提供如分支和循環這一類編程式功能,這是進行與表現相關判斷的基礎。

    在視圖中使用模板

    在學習了模板系統的基礎之后,現在讓我們使用相關知識來創建視圖。 重新打開我們在前一章在 mysite.views中創建的 current_datetime 視圖。 以下是其內容:

    from django.http import HttpResponse
    import datetime
    
    def current_datetime(request):
        now = datetime.datetime.now()
        html = "It is now %s." % now
        return HttpResponse(html)

    讓我們用 Django 模板系統來修改該視圖。 第一步,你可能已經想到了要做下面這樣的修改:

    from django.template import Template, Context
    from django.http import HttpResponse
    import datetime
    
    def current_datetime(request):
        now = datetime.datetime.now()
        t = Template("It is now {{ current_date }}.")
        html = t.render(Context({'current_date': now}))
        return HttpResponse(html)

    沒錯,它確實使用了模板系統,但是并沒有解決我們在本章開頭所指出的問題。 也就是說,模板仍然嵌入在Python代碼里,并未真正的實現數據與表現的分離。 讓我們將模板置于一個 單獨的文件 中,并且讓視圖加載該文件來解決此問題。

    你可能首先考慮把模板保存在文件系統的某個位置并用 Python 內建的文件操作函數來讀取文件內容。 假設文件保存在 /home/djangouser/templates/mytemplate.html 中的話,代碼就會像下面這樣:

    from django.template import Template, Context
    from django.http import HttpResponse
    import datetime
    
    def current_datetime(request):
        now = datetime.datetime.now()
        # Simple way of using templates from the filesystem.
        # This is BAD because it doesn't account for missing files!
        fp = open('/home/djangouser/templates/mytemplate.html')
        t = Template(fp.read())
        fp.close()
        html = t.render(Context({'current_date': now}))
        return HttpResponse(html)

    然而,基于以下幾個原因,該方法還算不上簡潔:

    • 它沒有對文件丟失的情況做出處理。 如果文件 mytemplate.html 不存在或者不可讀, open() 函數調用將會引發 IOError 異常。

    • 這里對模板文件的位置進行了硬編碼。 如果你在每個視圖函數都用該技術,就要不斷復制這些模板的位置。 更不用說還要帶來大量的輸入工作!

    • 它包含了大量令人生厭的重復代碼。 與其在每次加載模板時都調用 open() 、 fp.read() 和 fp.close() ,還不如做出更佳選擇。

    為了解決這些問題,我們采用了 模板自加載模板目錄 的技巧.

    模板加載

    為了減少模板加載調用過程及模板本身的冗余代碼,Django 提供了一種使用方便且功能強大的 API ,用于從磁盤中加載模板,

    要使用此模板加載API,首先你必須將模板的保存位置告訴框架。 設置的保存文件就是我們前一章節講述ROOT_URLCONF配置的時候提到的 settings.py。

    如果你是一步步跟隨我們學習過來的,馬上打開你的settings.py配置文件,找到TEMPLATE_DIRS這項設置吧。 它的默認設置是一個空元組(tuple),加上一些自動生成的注釋。

    TEMPLATE_DIRS = (
        # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
        # Always use forward slashes, even on Windows.
        # Don't forget to use absolute paths, not relative paths.
    )

    該設置告訴 Django 的模板加載機制在哪里查找模板。 選擇一個目錄用于存放模板并將其添加到TEMPLATE_DIRS 中:

    TEMPLATE_DIRS = (
        '/home/django/mysite/templates',
    )
    關閉
    程序員人生
    主站蜘蛛池模板: 欧美性猛交xxxxx水多 | 亚洲免费观看视频 | 国产成人在线视频网站 | 欧美xxxx黑人又粗又长 | 欧美一区二区三区成人 | 99这里只有精品视频 | 一区精品视频 | 精品久久久久久久久久 | 日韩免费一区 | 免费中文字幕在线 | 97精品一区二区三区 | 成人午夜毛片 | 81精品国产乱码久久久久久 | 炮机高潮痉挛哭叫失禁 | 国产1区 | 中文字幕视频在线观看 | 国产精品美女久久久久人 | 久久久久成人精品 | 久久国产成人 | 男人的天堂亚洲 | 国产在线高清 | 亚洲综合激情网 | 全部免费毛片在线播放网站 | 精品电影一区 | 成人性生活大片免费看一 | 欧美精品综合 | 成人免费视频播放 | 一区二区视频在线 | 精品一区视频 | 日日夜夜精 | 欧美久久视频 | 欧美成人一区二区三区片免费 | www.国产精品.com | 亚洲免费一区二区 | 看全色黄大色黄大片女图片第一次 | 亚洲波多野 | 久久久久久国产精品 | 中文字幕亚洲国产 | 午夜精品久久久久久久久久蜜桃 | 希岛あいり中文字幕在线 | 搞黄视频在线看 |