The Django Book

Chapter 4: The Django Template System

绗洓绔 Django妯℃澘绯荤粺

In the previous chapter, you may have noticed something peculiar in how we returned the text in our example views. Namely, the HTML was hard-coded directly in our Python code.

鍦ㄥ墠涓绔犱腑锛屼綘鍙兘宸茬粡娉ㄦ剰鍒版垜浠湪渚嬪瓙瑙嗗浘涓繑鍥炴枃鏈殑鏂瑰紡鏈夌偣鐗瑰埆銆備篃灏辨槸璇达紝HTML琚‖鎬у湴鐩存帴鍐欏叆 Python 浠g爜涔嬩腑銆

This arrangement leads to several problems:

杩欑澶勭悊浼氬鑷翠竴浜涢棶棰橈細

  • Any change to the design of the page requires a change to the Python code. The design of a site tends to change far more frequently than the underlying Python code, so it would be convenient if the the design could change without needing to modify the Python code.

  • 瀵归〉闈㈣璁¤繘琛岀殑浠讳綍鏀瑰彉閮藉繀椤诲 Python 浠g爜杩涜鐩稿簲鐨勪慨鏀广傜珯鐐硅璁$殑淇敼寰寰姣斿簳灞 Python 浠g爜鐨勪慨鏀硅棰戠箒寰楀锛屽洜姝ゅ鏋滃彲浠ュ湪涓嶈繘琛 Python 浠g爜淇敼鐨勬儏鍐典笅鍙樻洿璁捐锛岄偅灏嗕細鏂逛究寰楀銆

  • Writing Python code and designing HTML are two different disciplines, and most professional Web development environments split these responsibilities between separate people (or even separate departments). Designers and HTML/CSS coders shouldnt have to edit Python code to get their job done; they should deal with HTML.

  • Python 浠g爜缂栧啓鍜 HTML 璁捐鏄袱椤逛笉鍚岀殑宸ヤ綔锛屽ぇ澶氭暟涓撲笟鐨勭綉绔欏紑鍙戠幆澧冮兘灏嗕粬浠垎閰嶇粰涓嶅悓鐨勪汉鍛橈紙鐢氳嚦涓嶅悓閮ㄩ棬锛夋潵瀹屾垚銆傝璁′汉鍛樺拰 HTML/CSS 缂栧啓浜哄憳閮戒笉搴旇閫氳繃缂栬緫 Python 浠g爜鏉ュ畬鎴愯嚜宸辩殑宸ヤ綔锛涗粬浠簲璇ュ鐞嗙殑鏄 HTML銆

  • Similarly, its most efficient if programmers can work on Python code and designers can work on templates at the same time, rather than one person waiting for the other to finish editing a single file that contains both Python and HTML.

  • 鍚岀悊锛岀▼搴忓憳缂栧啓 Python 浠g爜鍜岃璁′汉鍛樺埗浣滄ā鏉垮悓鏃惰繘琛岀殑宸ヤ綔鏂瑰紡鏁堢巼鏄渶楂樼殑锛岃繙鑳滀簬璁╀竴涓汉绛夊緟鍙︿竴涓汉瀹屾垚瀵规煇涓棦鍖呭惈 Python 鍙堝寘鍚 HTML 鐨勬枃浠剁殑缂栬緫宸ヤ綔銆

For these reasons, its much cleaner and more maintainable to separate the design of the page from the Python code itself. We can do this with Djangos template system , which we discuss in this chapter.

鍩轰簬杩欎簺鍘熷洜锛屽皢椤甸潰鐨勮璁″拰Python鐨勪唬鐮佸垎绂诲紑浼氭洿骞插噣绠娲佹洿瀹规槗缁存姢銆傛垜浠彲浠ヤ娇鐢 Django鐨 妯℃澘绯荤粺 (Template System)鏉ュ疄鐜拌繖绉嶆ā寮忥紝杩欏氨鏄湰绔犺鍏蜂綋璁ㄨ鐨勯棶棰樸

Template System Basics

妯℃澘绯荤粺鍩烘湰鐭ヨ瘑

A Django template is a string of text that is intended to separate the presentation of a document from its data. A template defines placeholders and various bits of basic logic (i.e., template tags) that regulate how the document should be displayed. Usually, templates are used for producing HTML, but Django templates are equally capable of generating any text-based format.

妯℃澘绯荤粺鍩烘湰鐭ヨ瘑

Lets dive in with a simple example template. This template describes an HTML page that thanks a person for placing an order with a company. Think of it as a form letter:

璁╂垜浠繁鍏ュ垎鏋愪竴涓畝鍗曠殑渚嬪瓙妯℃澘銆傝妯℃澘鎻忚堪浜嗕竴涓悜鏌愪釜涓庡叕鍙哥鍗曚汉鍛樿嚧璋 HTML 椤甸潰銆傚彲灏嗗叾瑙嗕负涓涓牸寮忎俊鍑斤細

<html>
<head><title>Ordering notice</title></head>

<body>

<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>
{% endif %}

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

</body>
</html>

This template is basic HTML with some variables and template tags thrown in. Lets step through it:

璇ユā鏉挎槸涓娈垫坊鍔犱簡浜涜鍙橀噺鍜屾ā鏉挎爣绛剧殑鍩虹 HTML 銆傝鎴戜滑閫愬彞杩囦竴閬嶏細

Any text surrounded by a pair of braces (e.g., {{ person_name }} ) is a variable . This means insert the value of the variable with the given name. How do we specify the values of the variables? Well get to that in a moment.

鐢ㄤ袱涓ぇ鎷彿鎷捣鏉ョ殑鏂囧瓧锛堜緥濡 {{ person_name }} 锛夋槸 鍙橀噺(variable) 銆傝繖鎰忓懗鐫灏嗘寜鐓х粰瀹氱殑鍚嶅瓧鎻掑叆鍙橀噺鐨勫笺傚浣曟寚瀹氬彉閲忕殑鍊煎憿锛熺◢鍚庡氨浼氳鏄庛

Any text thats surrounded by curly braces and percent signs (e.g., {% if ordered_warranty %} ) is a template tag . The definition of a tag is quite broad: a tag just tells the template system to do something.

琚ぇ鎷彿鍜岀櫨鍒嗗彿鍖呭洿鐨勬枃鏈(渚嬪 {% if ordered_warranty %} )鏄 妯℃澘鏍囩(template tag) 銆傛爣绛(tag)瀹氫箟姣旇緝鏄庣‘锛屽嵆锛氫粎閫氱煡妯℃澘绯荤粺瀹屾垚鏌愪簺宸ヤ綔鐨勬爣绛俱

This example template contains two tags: the {% for item in item_list %} tag (a for tag) and the {% if ordered_warranty %} tag (an if tag).

杩欎釜绀轰緥妯℃澘鍖呭惈涓や釜鏍囩(tag): {% for item in item_list %} 鏍囩(涓涓 for 鏍囩) 鍜 {% if ordered_warranty %} 鏍囩 (涓涓 if 鏍囩)銆

A for tag acts as a simple loop construct, letting you loop over each item in a sequence. An if tag, as you may expect, acts as a logical if statement. In this particular case, the tag checks whether the value of the ordered_warranty variable evaluates to True . If it does, the template system will display everything between the {% if ordered_warranty %} and {% endif %} . If not, the template system wont display it. The template system also supports {% else %} and other various logic statements.

for 鏍囩鐢ㄤ簬鏋勫缓绠鍗曠殑寰幆锛屽厑璁镐綘閬嶅巻寰幆涓殑姣忎竴椤广 if 鏍囩锛屾濡備綘鎵鏂欙紝鏄敤鏉ユ墽琛岄昏緫鍒ゆ柇鐨勩傚湪杩欎釜渚嬪瓙涓爣绛炬娴 ordered_warranty 鍙橀噺鍊兼槸鍚︿负 True 銆 濡傛灉鏄紝妯℃澘绯荤粺灏嗘樉绀 {% if ordered_warranty %}{% endif %} 涔嬮棿鐨勬墍鏈夊唴瀹广 濡傛灉涓嶆槸妯℃澘绯荤粺涓嶄細鏄剧ず瀹冦傚畠褰撶劧涔熸敮鎸 {% else %} 浠ュ強鍏朵粬澶氱閫昏緫鍒ゆ柇鏂瑰紡銆

Finally, the second paragraph of this template has an example of a filter , with which you can alter the display of a variable. In this example, {{ ship_date|date:"F j, Y" }} , were passing the ship_date variable to the date filter, giving the date filter the argument "F j, Y" . The date filter formats dates in a given format, as specified by that argument. Filters are attached using a pipe character (| ), as a reference to Unix pipes.

鏈鍚庯紝杩欎釜妯℃澘鐨勭浜屾钀芥湁涓涓 filter 杩囨护鍣ㄧ殑渚嬪瓙,瀹冭兘璁╀綘鐢ㄦ潵杞崲鍙橀噺鐨勮緭鍑猴紝 鍦ㄨ繖涓緥瀛愪腑, {{ship_date|date:"F j, Y" }} 灏嗗彉閲 ship_datedate 杩囨护鍣ㄦ潵杞崲,杞崲鐨勫弬鏁版槸 "F j, Y" . date 杩囨护鍣ㄦ牴鎹寚瀹氱殑鍙傛暟杩涜鏍煎紡杈 鍑.杩囨护鍣ㄦ槸鐢ㄧ閬撳瓧绗( | )鏉ヨ皟鐢ㄧ殑,灏卞拰Unix绠¢亾涓鏍.

Each Django template has access to several built-in tags and filters, many of which are discussed in the sections that follow. Appendix F contains the full list of tags and filters, and its a good idea to familiarize yourself with that list so you know whats possible. Its also possible to create your own filters and tags, which we cover in Chapter 10.

Django 妯℃澘鍚湁寰堝鍐呯疆鐨則ags鍜宖ilters,鎴戜滑灏嗛檰缁繘琛屽涔. 闄勫綍F鍒楀嚭浜嗗緢澶氱殑tags鍜宖ilters鐨勫垪琛,鐔熸倝杩欎簺鍒楄〃瀵逛綘鏉ヨ鏄釜濂藉缓璁. 瀛︿範瀹岀鍗佺珷锛屼綘灏辨槑鐧芥庝箞鍘诲垱寤鸿嚜宸辩殑filters鍜宼ags浜.

Using the Template System

濡備綍浣跨敤妯℃澘绯荤粺

To use the template system in Python code, just follow these two steps:

鎯宠鍦≒ython浠g爜涓娇鐢ㄦā鏉跨郴缁燂紝鍙渶閬靛惊涓嬮潰涓や釜姝ラ锛

  1. Create a Template object by providing the raw template code as a string. Django also offers a way to create Template objects by designating the path to a template file on the filesystem; well examine that in a bit.

  1. 鍙互鐢ㄥ師濮嬬殑妯℃澘浠g爜瀛楃涓插垱寤轰竴涓 Template 瀵硅薄锛 Django鍚屾牱鏀寔鐢ㄦ寚瀹氭ā鏉挎枃浠惰矾寰勭殑鏂瑰紡鏉ュ垱寤 Template 瀵硅薄;

  1. Call the render() method of the Template object with a given set of variables (i.e., the context). This returns a fully rendered template as a string, with all of the variables and block tags evaluated according to the context.

  1. 璋冪敤 Template 瀵硅薄鐨 render() 鏂规硶骞舵彁渚涚粰浠栧彉閲(i.e., 鍐呭). 瀹冨皢杩斿洖涓涓畬鏁寸殑妯℃澘瀛楃涓插唴瀹,鍖呭惈浜嗘墍鏈夋爣绛惧潡涓庡彉閲忚В鏋愬悗鐨勫唴瀹.

The following sections describe each step in more detail.

浠ヤ笅閮ㄥ垎閫愭鐨勮缁嗕粙缁

Creating Template Objects

鍒涘缓妯℃澘瀵硅薄

The easiest way to create a Template object is to instantiate it directly. The Template class lives in the django.template module, and the constructor takes one argument, the raw template code. Lets dip into the Python interactive interpreter to see how this works in code.

鍒涘缓涓涓 Template 瀵硅薄鏈绠鍗曠殑鏂规硶灏辨槸鐩存帴瀹炰緥鍖栧畠銆 Template 绫诲氨鍦 django.template 妯″潡涓紝鏋勯犲嚱鏁版帴鍙椾竴涓弬鏁帮紝鍘熷妯℃澘浠g爜銆傝鎴戜滑娣卞叆鎸栨帢涓涓 Python鐨勮В閲婂櫒鐪嬬湅瀹冩槸鎬庝箞宸ヤ綔鐨勩

Interactive Interpreter Examples

浜や簰寮忕ず渚

Throughout this book, we feature example Python interactive interpreter sessions. You can recognize these examples by the triple greater-than signs (>>> ), which designate the interpreters prompt. If youre copying examples from this book, dont copy those greater-than signs.

鍦ㄦ湰涔︿腑锛屾垜浠枩娆㈢敤鍜孭ython瑙i噴鍣ㄧ殑浜や簰鏉ヤ妇渚嬨 浣犲彲浠ラ氳繃涓変釜> ( >>> ) 璇嗗埆瀹冧滑锛屽畠浠浉褰撲簬Python瑙i噴鍣ㄧ殑鎻愮ず绗︺ 濡傛灉浣犺鎷疯礉渚嬪瓙锛岃涓嶈鎷疯礉杩3涓>瀛楃銆

Multiline statements in the interactive interpreter are padded with three dots (... ), for example:

澶氳璇彞鍒欏湪鍓嶉潰鍔犱簡3涓皬鏁扮偣(... )锛屼緥濡傦細

>>> print """This is a
... string that spans
... three lines."""
This is a
string that spans
three lines.
>>> def my_function(value):
...     print value
>>> my_function('hello')
hello

Those three dots at the start of the additional lines are inserted by the Python shelltheyre not part of our input. We include them here to be faithful to the actual output of the interpreter. If you copy our examples to follow along, dont copy those dots.

杩3涓偣鏄疨ython瑙i噴鍣ㄨ嚜鍔ㄥ姞鍏ョ殑锛屼笉闇瑕佷綘鐨勮緭鍏ャ傛垜浠寘鍚畠浠槸涓轰簡蹇犲疄鍛堢幇瑙i噴鍣ㄧ殑 鐪熷疄杈撳嚭銆傚悓鏍烽亾鐞嗭紝鎷疯礉鏃朵笉瑕佹嫹璐濊繖3涓皬鏁扮偣绗﹀彿銆

From within the project directory created by django-admin.py startproject (as covered in Chapter 2), type python manage.py shell to start the interactive interpreter. Heres a basic walk-through:

杞埌project鐩綍锛堝湪绗簩绔犵敱 django-admin.py startproject 鍛戒护鍒涘缓锛夛紝 杈撳叆鍛戒护 python manage.py shell 鍚姩浜や簰鐣岄潰銆備笅闈㈡槸涓浜涘熀鏈搷浣滐細

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

If youre following along interactively, youll see something like this:

濡傛灉浣犺窡鎴戜滑涓璧峰仛锛屼綘灏嗕細鐪嬪埌涓嬮潰鐨勫唴瀹癸細

<django.template.Template object at 0xb7d5f24c>

That 0xb7d5f24c will be different every time, and it doesnt really matter; its simply the Python identity of the Template object.

0xb7d5f24c 姣忔閮戒細涓嶄竴鏍凤紝杩欐病浠涔堝叧绯伙紱杩欏彧鏄疨ython杩愯鏃 Template 瀵硅薄鐨処D銆

Django Settings

Django 璁剧疆

When using Django, you need to tell Django which settings to use. Interactively, this is typically done using python manage.py shell , but youve got a few other options described in Appendix E.

褰撲綘浣跨敤Django鏃讹紝浣犻渶瑕佸憡璇塂jango浣跨敤鍝釜閰嶇疆銆傚湪浜や簰妯″紡涓嬶紝閫氬父杩愯鍛戒护 python manage.py shell 鏉ュ仛杩欎釜锛岄檮褰旹閲岃繕鏈変竴浜涘叾浠栫殑涓浜涢夐」銆

When you create a Template object, the template system compiles the raw template code into an internal, optimized form, ready for rendering. But if your template code includes any syntax errors, the call to Template() will cause a TemplateSyntaxError exception:

褰撲綘鍒涘缓涓涓 Template 瀵硅薄锛屾ā鏉跨郴缁熷湪鍐呴儴缂栬瘧杩欎釜妯℃澘鍒板唴閮ㄦ牸寮忥紝骞跺仛浼樺寲锛屽仛濂 娓叉煋鐨勫噯澶囥傚鏋滀綘鐨勬ā鏉胯娉曟湁閿欒锛岄偅涔堝湪璋冪敤 Template() 鏃跺氨浼氭姏鍑 TemplateSyntaxError 寮傚父锛

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

The system raises a TemplateSyntaxError exception for any of the following cases:

绯荤粺浼氬湪涓嬮潰鐨勬儏褰㈡姏鍑 TemplateSyntaxError 寮傚父锛

  • Invalid block tags

  • 鏃犳晥鐨勫潡鏍囩

  • Invalid arguments to valid block tags

  • 鏃犳晥鐨勫弬鏁

  • Invalid filters

  • 鏃犳晥鐨勮繃婊ゅ櫒

  • Invalid arguments to valid filters

  • 杩囨护鍣ㄧ殑鍙傛暟鏃犳晥

  • Invalid template syntax

  • 鏃犳晥鐨勬ā鏉胯娉

  • Unclosed block tags (for block tags that require closing tags)

  • 鏈皝闂殑鍧楁爣绛 锛堥拡瀵归渶瑕佸皝闂殑鍧楁爣绛撅級

Rendering a Template

妯℃澘娓叉煋

Once you have a Template object, you can pass it data by giving it a context . A context is simply a set of variables and their associated values. A template uses this to populate its variable tags and evaluate its block tags.

涓鏃︿綘鍒涘缓涓涓 Template 瀵硅薄锛屼綘鍙互鐢 context 鏉ヤ紶閫掓暟鎹粰瀹冦 涓涓猚ontext鏄竴绯诲垪鍙橀噺鍜屽畠浠肩殑闆嗗悎銆傛ā鏉夸娇鐢ㄥ畠鏉ヨ祴鍊兼ā鏉垮彉閲忔爣绛惧拰 鎵ц鍧楁爣绛俱

A context is represented in Django by the Context class, which lives in the django.template module. Its constructor takes one optional argument: a dictionary mapping variable names to variable values. Call the Template objects render() method with the context to fill the template:

context鍦―jango閲岃〃鐜颁负 Context 绫伙紝鍦 django.template 妯″潡閲屻 瀹冩瀯閫犳槸鏈変竴涓彲閫夊弬鏁帮細涓涓瓧鍏告槧灏勫彉閲忓拰瀹冧滑鐨勫笺傝皟鐢 Template 瀵硅薄 鐨 render() 鏂规硶骞朵紶閫抍ontext鏉ュ~鍏呮ā鏉匡細

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

Dictionaries and Contexts

瀛楀吀鍜孋ontexts

A Python dictionary is a mapping between known keys and variable values. A Context is similar to a dictionary, but a Context provides additional functionality, as covered in Chapter 10.

Python鐨勫瓧鍏告暟鎹被鍨嬪氨鏄叧閿瓧鍜屽畠浠肩殑涓涓槧灏勩 Context 鍜屽瓧鍏稿緢绫讳技锛 Context 杩樻彁渚涙洿澶氱殑鍔熻兘锛岃鐪嬬鍗佺珷銆

Variable names must begin with a letter (A-Z or a-z) and may contain digits, underscores, and dots. (Dots are a special case well get to in a moment.) Variable names are case sensitive.

鍙橀噺鍚嶅繀椤荤敱鑻辨枃瀛楃寮濮 锛圓-Z鎴朼-z锛夊苟鍙互鍖呭惈鏁板瓧瀛楃銆佷笅鍒掔嚎鍜屽皬鏁扮偣銆 锛堝皬鏁扮偣鍦ㄨ繖閲屾湁鐗瑰埆鐨勭敤閫旓紝绋嶅悗鎴戜滑浼氳鍒帮級鍙橀噺鏄ぇ灏忓啓鏁忔劅鐨勩

Heres an example of template compilation and rendering, using the sample template from the beginning of this chapter:

涓嬮潰鏄紪鍐欐ā鏉垮苟娓叉煋鐨勭ず渚嬶細

>>> from django.template import Template, Context
>>> raw_template = """<p>Dear {{ person_name }},</p>
...
... <p>Thanks for ordering {{ product }} from {{ company }}. It's scheduled
... to ship on {{ ship_date|date:"F j, Y" }}.</p>
...
... {% if ordered_warranty %}
... <p>Your warranty information will be included in the packaging.</p>
... {% endif %}
...
... <p>Sincerely,<br />{{ company }}</p>"""
>>> t = Template(raw_template)
>>> import datetime
>>> c = Context({'person_name': 'John Smith',
...     'product': 'Super Lawn Mower',
...     'company': 'Outdoor Equipment',
...     'ship_date': datetime.date(2009, 4, 2),
...     'ordered_warranty': True})
>>> t.render(c)
"<p>Dear John Smith,</p>\n\n<p>Thanks for ordering Super Lawn Mower from
Outdoor Equipment. It's scheduled \nto ship on April 2, 2009.</p>\n\n\n
<p>Your warranty information will be included in the packaging.</p>\n\n\n
<p>Sincerely,<br />Outdoor Equipment</p>"

Lets step through this code one statement at a time:

璁╂垜浠愬彞鐪嬬湅杩欐浠g爜锛

First, we import the classes Template and Context , which both live in the module django.template .

棣栧厛鎴戜滑瀵煎叆 锛坕mport锛夌被 TemplateContext 锛屽畠浠兘鍦ㄦā鍧 django.template 閲屻

We save the raw text of our template into the variable raw_template . Note that we use triple quote marks to designate the string, because it wraps over multiple lines; in Python codde, strings designated with single quote marks cannot be wrapped over multiple lines.

鎴戜滑鎶婃ā鏉垮師濮嬫枃鏈繚瀛樺埌鍙橀噺 raw_template 銆傛敞鎰忓埌鎴戜滑浣跨敤浜嗕笁涓紩鍙锋潵 鏍囪瘑杩欎簺鏂囨湰锛屽洜涓鸿繖鏍峰彲浠ュ寘鍚琛屻傝繖鏄疨ython鐨勪竴涓娉曘

Next, we create a template object, t , by passing raw_template to the Template class constructor.

鎺ヤ笅鏉ワ紝鎴戜滑鍒涘缓浜嗕竴涓ā鏉垮璞 t 锛屾妸 raw_template 浣滀负 Template 绫 鐨勬瀯閫犵殑鍙傛暟銆

We import the datetime module from Pythons standard library, because well need it in the following statement.

鎴戜滑浠嶱ython鐨勬爣鍑嗗簱瀵煎叆 datetime 妯″潡锛屼互鍚庢垜浠皢浼氫娇鐢ㄥ畠銆

Then, we create a Context object, c . The Context constructor takes a Python dictionary, which maps variable names to values. Here, for example, we specify that the person_name is 'John Smith' , product is 'Super Lawn Mower' , and so forth.

鐒跺悗锛屾垜浠垱寤轰竴涓 Context 瀵硅薄锛 cContext 鏋勯犵殑鍙傛暟鏄疨ython 瀛楀吀鏁版嵁绫诲瀷锛屽湪杩欓噷锛屾垜浠粰鐨勫弬鏁版槸 person_name 鍊间负 'John Smith' , product 鍊间负 'Super Lawn Mower' 锛岀瓑绛夈

Finally, we call the render() method on our template object, passing it the context. This returns the rendered templatethat is, it replaces template variables with the actual values of the variables, and it executes any block tags.

鏈鍚庯紝鎴戜滑鍦ㄦā鏉垮璞′笂璋冪敤 render() 鏂规硶锛屼紶閫 context鍙傛暟缁欏畠銆 杩欐槸杩斿洖娓叉煋鍚庣殑妯℃澘鐨勬柟娉曪紝瀹冧細鏇挎崲妯℃澘鍙橀噺涓虹湡瀹炵殑鍊煎拰鎵ц鍧楁爣绛俱

Note that the warranty paragraph was displayed because the ordered_warranty variable evaluated to True . Also note the date, April 2, 2009 , which is displayed according to the format string 'F j, Y' . (We explain format strings for the date filter shortly.)

娉ㄦ剰锛寃arranty paragraph鏄剧ず鏄洜涓 ordered_warranty 鐨勫间负 True . 娉ㄦ剰鏃堕棿鐨勬樉绀猴紝 April 2, 2009 , 瀹冩槸鎸 'F j, Y' 鏍煎紡鏄剧ず鐨勩 锛堟垜浠緢蹇氨浼氬湪 date 杩囨护鍣ㄨВ閲婅繖浜涙牸寮忥級

If youre new to Python, you may wonder why this output includes newline characters ('\n' ) rather than displaying the line breaks. Thats happening because of a subtlety in the Python interactive interpreter: the call to t.render(c) returns a string, and by default the interactive interpreter displays the representation of the string, rather than the printed value of the string. If you want to see the string with line breaks displayed as true line breaks rather than '\n' characters, use the print statement: print t.render(c) .

濡傛灉浣犳槸Python鍒濆鑰咃紝浣犲彲鑳藉湪鎯充负浠涔堣緭鍑洪噷鏈夊洖杞︽崲琛岀殑瀛楃('\n' )鑰屼笉鏄 鏄剧ず鍥炶溅鎹㈣锛熷洜涓鸿繖鏄疨ython浜や簰瑙i噴鍣ㄧ殑缂樻晠锛氳皟鐢 t.render(c) 杩斿洖瀛楃涓诧紝 瑙i噴鍣ㄧ己鐪佹樉绀鸿繖浜涘瓧绗︿覆鐨 鐪熷疄鍐呭鍛堢幇 锛岃屼笉鏄墦鍗拌繖涓彉閲忕殑鍊笺 瑕佹樉绀烘崲琛岃屼笉鏄 '\n' 锛屼娇鐢 print 璇彞锛 print t.render(c)

Those are the fundamentals of using the Django template system: just write a template, create a Template object, create a Context , and call the render() method.

杩欏氨鏄娇鐢―jango妯℃澘绯荤粺鐨勫熀鏈鍒欙細鍐欐ā鏉匡紝鍒涘缓 Template 瀵硅薄锛屽垱寤 Context 锛 璋冪敤 render() 鏂规硶銆

Multiple Contexts, Same Template

鍚屼竴妯℃澘锛屽涓笂涓嬫枃

Once you have a Template object, you can render multiple contexts through it, for example:

涓鏃︽湁浜 妯℃澘 瀵硅薄锛屼綘灏卞彲浠ラ氳繃瀹冩覆鏌撳涓儗鏅紙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

Whenever youre using the same template source to render multiple contexts like this, its more efficient to create the Template object once , and then call render() on it multiple times:

鏃犺浣曟椂鍍忚繖鏍蜂娇鐢ㄥ悓涓妯℃澘婧愭覆鏌撳涓儗鏅紝鍙垱寤 涓娆 妯℃澘 瀵硅薄锛岀劧鍚庡瀹冨娆¤皟鐢 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}))

Djangos template parsing is quite fast. Behind the scenes, most of the parsing happens via a single call to a short regular expression. This is in stark contrast to XML-based template engines, which incur the overhead of an XML parser and tend to be orders of magnitude slower than Djangos template rendering engine.

Django 妯℃澘瑙f瀽闈炲父蹇嵎銆傚ぇ閮ㄥ垎鐨勮В鏋愬伐浣滈兘鏄湪鍚庡彴閫氳繃瀵圭畝鐭鍒欒〃杈惧紡涓娆℃ц皟鐢ㄦ潵瀹屾垚銆傝繖鍜屽熀浜 XML 鐨勬ā鏉垮紩鎿庡舰鎴愰矞鏄庡姣旓紝閭d簺寮曟搸鎵挎媴浜 XML 瑙f瀽鍣ㄧ殑寮閿锛屼笖寰寰姣 Django 妯℃澘娓叉煋寮曟搸瑕佹參涓婂嚑涓暟閲忕骇銆

Context Variable Lookup

鑳屾櫙鍙橀噺鐨勬煡鎵

In the examples so far, weve passed simple values in the contextsmostly strings, plus a datetime.date example. However, the template system elegantly handles more complex data structures, such as lists, dictionaries, and custom objects.

鍦ㄥ埌鐩墠涓烘鐨勪緥瀛愪腑锛屾垜浠氳繃 context 浼犻掔殑绠鍗曞弬鏁板间富瑕佹槸瀛楃涓诧紝杩樻湁涓涓 datetime.date 鑼冧緥銆傜劧鑰岋紝妯℃澘绯荤粺鑳藉闈炲父绠娲佸湴澶勭悊鏇村姞澶嶆潅鐨勬暟鎹粨鏋勶紝渚嬪list銆乨ictionary鍜岃嚜瀹氫箟鐨勫璞°

The key to traversing complex data structures in Django templates is the dot character (. ). Use a dot to access dictionary keys, attributes, indices, or methods of an object.

鍦 Django 妯℃澘涓亶鍘嗗鏉傛暟鎹粨鏋勭殑鍏抽敭鏄彞鐐瑰瓧绗 (.)銆備娇鐢ㄥ彞鐐瑰彲浠ヨ闂瓧鍏哥殑閿笺佸睘鎬с佺储寮曞拰瀵硅薄鐨勬柟娉曘

This is best illustrated with a few examples. For instance, suppose youre passing a Python dictionary to a template. To access the values of that dictionary by dictionary key, use a dot:

鏈濂芥槸鐢ㄥ嚑涓緥瀛愭潵璇存槑涓涓嬨傛瘮濡傦紝鍋囪浣犺鍚戞ā鏉夸紶閫掍竴涓 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)
'Sally is 43 years old.'

Similarly, dots also allow access of object attributes. For example, a Python datetime.date object has year , month , and day attributes, and you can use a dot to access those attributes in a Django template:

鍚屾牱锛屼篃鍙互閫氳繃鍙ョ偣鏉ヨ闂璞$殑灞炴с傛瘮鏂硅锛 Python 鐨 datetime.date 瀵硅薄鏈 yearmonthday 鍑犱釜灞炴э紝浣犲悓鏍峰彲浠ュ湪妯℃澘涓娇鐢ㄥ彞鐐规潵璁块棶杩欎簺灞炴э細

>>> 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)
'The month is 5 and the year is 1993.'

This example uses a custom class:

涓嬩緥浣跨敤浜嗕竴涓嚜瀹氫箟绫伙細

>>> 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)
'Hello, John Smith.'

Dots are also used to call methods on objects. For example, each Python string has the methods upper() and isdigit() , and you can call those in Django templates using the same dot syntax:

鍙ョ偣杩樼敤浜庤皟鐢ㄥ璞$殑鏂规硶銆備緥濡傦紝姣忎釜 Python 瀛楃涓查兘鏈 upper()isdigit() 鏂规硶锛屼綘鍦ㄦā鏉夸腑鍙互浣跨敤鍚屾牱鐨勫彞鐐硅娉曟潵璋冪敤瀹冧滑锛

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

Note that you dont include parentheses in the method calls. Also, its not possible to pass arguments to the methods; you can only call methods that have no required arguments. (We explain this philosophy later in this chapter.)

娉ㄦ剰浣犱笉鑳藉湪鏂规硶璋冪敤涓娇鐢ㄥ渾鎷彿銆傝屼笖涔熸棤娉曠粰璇ユ柟娉曚紶閫掑弬鏁帮紱浣犲彧鑳借皟鐢ㄤ笉闇鍙傛暟鐨勬柟娉曘傦紙鎴戜滑灏嗗湪鏈珷绋嶅悗閮ㄥ垎瑙i噴璇ヨ璁¤銆傦級

Finally, dots are also used to access list indices, for example:

鏈鍚庯紝鍙ョ偣涔熷彲鐢ㄤ簬璁块棶鍒楄〃绱㈠紩锛屼緥濡傦細

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

Negative list indices are not allowed. For example, the template variable {{ items.-1 }} would cause a TemplateSyntaxError .

涓嶅厑璁镐娇鐢ㄨ礋鏁板垪琛ㄧ储寮曘傚儚 {{ items.-1 }} 杩欐牱鐨勬ā鏉垮彉閲忓皢浼氬紩鍙

TemplateSyntaxError 寮傚父銆

Python Lists

Python 鍒楄〃绫诲瀷

Python lists have 0-based indices so that the first item is at index 0, the second is at index 1, and so on.

Python鍒楄〃绫诲瀷鐨勭储寮曟槸浠0寮濮嬬殑锛岀涓涓厓绱犵殑绱㈠紩鏄0锛岀浜屼釜鏄1锛屼互姝ょ被鎺ㄣ

The dot lookups can be summarized like this: when the template system encounters a dot in a variable name, it tries the following lookups, in this order:

鍙ョ偣鏌ユ壘瑙勫垯鍙鎷负锛氬綋妯℃澘绯荤粺鍦ㄥ彉閲忓悕涓亣鍒扮偣鏃讹紝鎸夌収浠ヤ笅椤哄簭灏濊瘯杩涜鏌ユ壘锛

  • Dictionary lookup (e.e., foo["bar"] )

  • 瀛楀吀鏌ユ壘 锛堟瘮濡 foo["bar"] )

  • Attribute lookup (e.g., foo.bar )

  • 灞炴ф煡鎵 (姣斿 foo.bar )

  • Method call (e.g., foo.bar() )

  • 鏂规硶璋冪敤 锛堟瘮濡 foo.bar() )

  • List-index lookup (e.g., foo[bar] )

  • 鍒楄〃绫诲瀷绱㈠紩鏌ユ壘 (姣斿 foo[bar] )

The system uses the first lookup type that works. Its short-circuit logic.

绯荤粺浣跨敤鎵鎵惧埌鐨勭涓涓湁鏁堢被鍨嬨傝繖鏄竴绉嶇煭璺昏緫銆

Dot lookups can be nested multiple levels deep. For instance, the following example uses {{ person.name.upper }} , which translates into a dictionary lookup (person['name'] ) and then a method call (upper() ):

鍙ョ偣鏌ユ壘鍙互澶氱骇娣卞害宓屽銆備緥濡傚湪涓嬮潰杩欎釜渚嬪瓙涓 {{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)
'SALLY is 43 years old.'
Method Call Behavior
鏂规硶璋冪敤琛屼负

Method calls are slightly more complex than the other lookup types. Here are some things to keep in mind:

鏂规硶璋冪敤姣斿叾浠栫被鍨嬬殑鏌ユ壘鐣ヤ负澶嶆潅涓鐐广備互涓嬫槸涓浜涙敞鎰忎簨椤癸細

If, during the method lookup, a method raises an exception, the exception will be propagated, unless the exception has an attribute silent_variable_failure whose value is True . If the exception does have a silent_variable_failure attribute, the variable will render as an empty string, for example:

鍦ㄦ柟娉曟煡鎵捐繃绋嬩腑锛屽鏋滄煇鏂规硶鎶涘嚭涓涓紓甯革紝闄ら潪璇ュ紓甯告湁涓涓 silent_variable_failure 灞炴у苟涓斿间负 True 锛屽惁鍒欑殑璇濆畠灏嗚浼犳挱銆傚鏋滆寮傚父 纭湁 灞炴 silent_variable_failure 锛岄偅涔堬紙鎵鏌ユ壘锛夊彉閲忓皢琚覆鏌撲负绌哄瓧绗︿覆锛屼緥濡傦細

>>> 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}))
"My name is ."

A method call will only work if the method has no required arguments. Otherwise, the system will move to the next lookup type (list-index lookup).

浠呭湪鏂规硶鏃犻渶浼犲叆鍙傛暟鏃讹紝鍏惰皟鐢ㄦ墠鏈夋晥銆傚惁鍒欙紝绯荤粺灏嗕細杞Щ鍒颁笅涓涓煡鎵剧被鍨嬶紙鍒楄〃绱㈠紩鏌ユ壘锛夈

Obviously, some methods have side effects, and it would be foolish at best, and possibly even a security hole, to allow the template system to access them.

鏄剧劧锛屾湁浜涙柟娉曟槸鏈夊壇浣滅敤鐨勶紝濂界殑鎯呭喌涓嬪厑璁告ā鏉跨郴缁熻闂畠浠彲鑳藉彧鏄共浠惰牏浜嬶紝鍧忕殑鎯呭喌涓嬬敋鑷充細寮曞彂瀹夊叏婕忔礊銆

Say, for instance, you have a BankAccount object that has a delete() method. A template shouldnt be allowed to include something like {{ account.delete }} .

渚嬪锛屼綘鐨勪竴涓 BankAccount 瀵硅薄鏈変竴涓 delete() 鏂规硶銆備笉搴旇鍏佽妯℃澘鍖呭惈鍍 {{account.delete}} 杩欐牱鐨勬柟娉曡皟鐢ㄣ

To prevent this, set the function attribute alters_data on the method:

瑕侀槻姝㈣繖鏍风殑浜嬫儏鍙戠敓锛屽繀椤昏缃鏂规硶鐨 alters_data 鍑芥暟灞炴э細

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

The template system wont execute any method marked in this way. In other words, if a template includes {{ account.delete }} , that tag will not execute the delete() method. It will fail silently.

妯℃澘绯荤粺涓嶄細鎵ц浠讳綍浠ヨ鏂瑰紡杩涜鏍囪鐨勬柟娉曘備篃灏辨槸璇达紝濡傛灉妯℃澘鍖呭惈浜 {{account.delete}} ,璇ユ爣绛句笉浼氳皟鐢 delete() 鏂规硶銆傚畠鍙細瀹夐潤鍦板け璐ワ紙骞朵笉浼氬紩鍙戝紓甯革級銆

How Invalid Variables Are Handled
濡備綍澶勭悊鏃犳晥鍙橀噺

By default, if a variable doesnt exist, the template system renders it as an empty string, failing silently, for example:

榛樿鎯呭喌涓嬶紝濡傛灉涓涓彉閲忎笉瀛樺湪锛屾ā鏉跨郴缁熶細鎶婂畠灞曠ず涓虹┖瀛楃涓诧紝涓嶅仛浠讳綍浜嬫儏鍦拌〃绀哄け璐ワ紝渚嬪锛

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

The system fails silently rather than raising an exception because its intended to be resilient to human error. In this case, all of the lookups failed because variable names have the wrong case or name. In the real world, its unacceptable for a Web site to become inaccessible due to a small template syntax error.

绯荤粺闈欐倓鎮勫湴琛ㄧず澶辫触锛岃屼笉鏄紩鍙戜竴涓紓甯革紝鍥犱负杩欓氬父鏄汉涓洪敊璇犳垚鐨勩傝繖绉嶆儏鍐典笅锛屽洜涓哄彉閲忓悕鏈夐敊璇殑鐘跺喌鎴栧悕绉帮紝 鎵鏈夌殑鏌ヨ閮戒細澶辫触銆傜幇瀹炰笘鐣屼腑锛屽浜庝竴涓獁eb绔欑偣鏉ヨ锛屽鏋滀粎浠呭洜涓轰竴涓皬鐨勬ā鏉胯娉曢敊璇岄犳垚鏃犳硶璁块棶锛岃繖鏄笉鍙帴鍙楃殑銆

Note that its possible to change Djangos default behavior in this regard, by tweaking a setting in your Django configuration. We discuss this further in Chapter 10.

娉ㄦ剰锛屾垜浠槸鍙互鏈夋満浼氶氳繃鏇存敼Django鐨勯厤缃互鍦ㄨ繖鐐逛笂鏀瑰彉Django鐨勯粯璁よ涓虹殑銆 鎴戜滑浼氬湪绗10绔犺繘琛岃繘涓姝ョ殑璁ㄨ鐨勩

Playing with Context Objects

鐜╀竴鐜╀笂涓嬫枃(context)瀵硅薄

Most of the time, youll instantiate Context objects by passing in a fully populated dictionary to Context() . But you can add and delete items from a Context object once its been instantiated, too, using standard Python dictionary syntax:

澶氭暟鏃堕棿锛屼綘鍙互閫氳繃浼犻掍竴涓畬鍏ㄥ~鍏(full populated)鐨勫瓧鍏哥粰 Context() 鏉ュ垵濮嬪寲 涓婁笅鏂(Context) 銆 浣嗘槸鍒濆鍖栦互鍚庯紝浣犱篃鍙互浠巂`涓婁笅鏂(Context)`` 瀵硅薄娣诲姞鎴栬呭垹闄ゆ潯鐩紝浣跨敤鏍囧噯鐨凱ython瀛楀吀璇硶(syntax):

>>> from django.template import Context
>>> c = Context({"foo": "bar"})
>>> c['foo']
'bar'
>>> del c['foo']
>>> c['foo']
''
>>> c['newvariable'] = 'hello'
>>> c['newvariable']
'hello'

Basic Template Tags and Filters

鍩烘湰鐨勬ā鏉挎爣绛惧拰杩囨护鍣

As weve mentioned already, the template system ships with built-in tags and filters. The sections that follow provide a rundown of the most common tags and filters.

鍍忔垜浠互鍓嶆彁鍒拌繃鐨勶紝妯℃澘绯荤粺甯︽湁鍐呯疆鐨勬爣绛惧拰杩囨护鍣ㄣ 涓嬮潰鐨勭珷鑺傛彁渚涗簡涓涓鏁伴氱敤鏍囩鍜岃繃婊ゅ櫒鐨勭畝瑕佽鏄庛

Tags

鏍囩

if/else
if/else

The {% if %} tag evaluates a variable, and if that variable is true (i.e., it exists, is not empty, and is not a false Boolean value), the system will display everything between {% if %} and {% endif %} , for example:

{% if %} 鏍囩妫鏌(evaluate)涓涓彉閲忥紝濡傛灉杩欎釜鍙橀噺涓虹湡锛堝嵆锛屽彉閲忓瓨鍦紝闈炵┖锛屼笉鏄竷灏斿煎亣锛夛紝绯荤粺浼氭樉绀哄湪 {% if %}{% endif %} 涔嬮棿鐨勪换浣曞唴瀹癸紝渚嬪锛

{% if today_is_weekend %}
    <p>Welcome to the weekend!</p>
{% endif %}

An {% else %} tag is optional:

{% else %} 鏍囩鏄彲閫夌殑锛

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

Python Truthiness

Python 鐨勨滅湡鍊尖

In Python, the empty list ([] ), tuple (() ), dictionary ({} ), string ('' ), zero (0 ), and the special object None are False in a Boolean context. Everything else is True .

鍦╬ython涓┖鐨勫垪琛 ( [] )锛宼uple( () )锛屽瓧鍏( {} )锛屽瓧绗︿覆( '' )锛岄浂( 0 )锛岃繕鏈 None 瀵硅薄锛屽湪閫昏緫鍒ゆ柇涓兘涓哄亣锛屽叾浠栫殑鎯呭喌閮戒负鐪熴

The {% if %} tag accepts and , or , or not for testing multiple variables, or to negate a given variable. For example:

{% if %} 鏍囩鎺ュ彈 andor 鎴栬 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. (OK, so
    writing English translations of Boolean logic sounds
    stupid; it's not our fault.)
{% endif %}

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

{% if %} tags dont allow and and or clauses within the same tag, because the order of logic would be ambiguous. For example, this is invalid:

{% if %} 鏍囩涓嶅厑璁稿湪鍚屼竴涓爣绛句腑鍚屾椂浣跨敤 andor 锛屽洜涓洪昏緫涓婂彲鑳芥ā绯婄殑锛屼緥濡傦紝濡備笅绀轰緥鏄敊璇殑锛

{% if athlete_list and coach_list or cheerleader_list %}

The use of parentheses for controlling order of operations is not supported. If you find yourself needing parentheses, consider performing logic in the view code in order to simplify the templates. Even so, if you need to combine and and or to do advanced logic, just use nested {% if %} tags, for example:

绯荤粺涓嶆敮鎸佺敤鍦嗘嫭鍙锋潵缁勫悎姣旇緝鎿嶄綔銆傚鏋滀綘鍙戠幇闇瑕佺粍鍚堟搷浣滐紝浣犲彲浠ヨ冭檻鐢ㄩ昏緫璇彞鏉ョ畝鍖 妯℃澘鐨勫鐞嗐備緥濡傦紝浣犻渶瑕佺粍鍚 andor 鍋氫簺澶嶆潅閫昏緫鍒ゆ柇锛屽彲浠ヤ娇鐢ㄥ祵濂楃殑 {% if %} 鏍囩锛岀ず渚嬪涓嬶細

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

Multiple uses of the same logical operator are fine, but you cant combine different operators. For example, this is valid:

澶氭浣跨敤鍚屼竴涓昏緫鎿嶄綔绗︽槸娌℃湁闂鐨勶紝浣嗘槸鎴戜滑涓嶈兘鎶婁笉鍚岀殑鎿嶄綔绗︾粍鍚堣捣鏉ャ傛瘮濡傝繖鏍风殑浠g爜鏄病闂鐨勶細

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

There is no {% elif %} tag. Use nested {% if %} tags to accomplish the same thing:

骞舵病鏈 {% elif %} 鏍囩锛岃浣跨敤宓屽鐨 {% if %} 鏍囩鏉ヨ揪鎴愬悓鏍风殑鏁堟灉锛

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

Make sure to close each {% if %} with an {% endif %} . Otherwise, Django will throw a TemplateSyntaxError .

涓瀹氳鐢 {% endif %} 鍏抽棴姣忎竴涓 {% if %} 鏍囩銆傚惁鍒橠jango浼氭姏鍑 TemplateSyntaxError

for
for

The {% for %} tag allows you to loop over each item in a sequence. As in Pythons for statement, the syntax is for X in Y , where Y is the sequence to loop over and X is the name of the variable to use for a particular cycle of the loop. Each time through the loop, the template system will render everything between {% for %} and {% endfor %} .

{% for %} 鍏佽鎴戜滑鍦ㄤ竴涓簭鍒椾笂杩唬銆備笌Python鐨 for 璇彞鐨勬儏褰㈢被浼硷紝寰幆璇硶鏄 for X in Y 锛孻鏄杩唬鐨勫簭鍒楄孹鏄湪姣忎竴涓壒瀹氱殑寰幆涓娇鐢ㄧ殑鍙橀噺鍚嶇О銆傛瘡涓娆″惊鐜腑锛屾ā鏉跨郴缁熶細娓叉煋鍦 {% for %}{% endfor %} 涔嬮棿鐨勬墍鏈夊唴瀹广

For example, you could use the following to display a list of athletes given a variable athlete_list :

渚嬪锛岀粰瀹氫竴涓繍鍔ㄥ憳鍒楄〃 athlete_list 鍙橀噺锛屾垜浠彲浠ヤ娇鐢ㄤ笅闈㈢殑浠g爜鏉ユ樉绀鸿繖涓垪琛細

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

Add reversed to the tag to loop over the list in reverse:

缁欐爣绛惧鍔犱竴涓 reversed 浣垮緱璇ュ垪琛ㄨ鍙嶅悜杩唬锛

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

Its possible to nest {% for %} tags:

鍙互宓屽浣跨敤 {% for %} 鏍囩锛

{% for country in countries %}
    <h1>{{ country.name }}</h1>
    <ul>
    {% for city in country.city_list %}
        <li>{{ city }}</li>
    {% endfor %}
    </ul>
{% endfor %}

There is no support for breaking out of a loop before the loop is finished. If you want to accomplish this, change the variable youre looping over so that it includes only the values you want to loop over. Similarly, there is no support for a continue statement that would instruct the loop processor to return immediately to the front of the loop. (See the section Philosophies and Limitations later in this chapter for the reasoning behind this design decision.)

Django涓嶆敮鎸侀鍑哄惊鐜搷浣溿傚鏋滄垜浠兂閫鍑哄惊鐜紝鍙互鏀瑰彉姝e湪杩唬鐨勫彉閲忥紝璁╁叾浠呬粎鍖呭惈闇瑕佽凯浠g殑椤圭洰銆傚悓鐞嗭紝Django涔熶笉鏀寔continue璇彞锛屾垜浠棤娉曡褰撳墠杩唬鎿嶄綔璺冲洖鍒板惊鐜ご閮ㄣ傦紙璇峰弬鐪嬫湰绔犵◢鍚庣殑鐞嗗康鍜岄檺鍒跺皬鑺傦紝浜嗚В涓嬪喅瀹氳繖涓璁$殑鑳屽悗鍘熷洜锛

The {% for %} tag sets a magic forloop template variable within the loop. This variable has a few attributes that give you information about the progress of the loop:

{% for %} 鏍囩鍦ㄥ惊鐜腑璁剧疆浜嗕竴涓壒娈婄殑 forloop 妯℃澘鍙橀噺銆傝繖涓彉閲忚兘鎻愪緵涓浜涘綋鍓嶅惊鐜繘灞曠殑淇℃伅锛

forloop.counter is always set to an integer representing the number of times the loop has been entered. This is one-indexed, so the first time through the loop, forloop.counter will be set to 1 . Heres an example:

forloop.counter 鎬绘槸涓涓〃绀哄綋鍓嶅惊鐜殑鎵ц娆℃暟鐨勬暣鏁拌鏁板櫒銆傝繖涓鏁板櫒鏄粠1寮濮嬬殑锛屾墍浠ュ湪绗竴娆″惊鐜椂 forloop.counter 灏嗕細琚缃负1銆備緥瀛愬涓嬶細

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

forloop.counter0 is like forloop.counter , except its zero-indexed. Its value will be set to 0 the first time through the loop.

forloop.counter0 绫讳技浜 forloop.counter 锛屼絾鏄畠鏄粠0璁℃暟鐨勩傜涓娆℃墽琛屽惊鐜椂杩欎釜鍙橀噺浼氳璁剧疆涓0銆

forloop.revcounter is always set to an integer representing the number of remaining items in the loop. The first time through the loop, forloop.revcounter will be set to the total number of items in the sequence youre traversing. The last time through the loop, forloop.revcounter will be set to 1 .

forloop.revcounter 鏄〃绀哄惊鐜腑鍓╀綑椤圭殑鏁村瀷鍙橀噺銆傚湪寰幆鍒濇鎵ц鏃 forloop.revcounter 灏嗚璁剧疆涓哄簭鍒椾腑椤圭殑鎬绘暟銆傛渶鍚庝竴娆″惊鐜墽琛屼腑锛岃繖涓彉閲忓皢琚疆1銆

forloop.revcounter0 is like forloop.revcounter , except its zero-indexed. The first time through the loop, forloop.revcounter0 will be set to the number of elements in the sequence minus 1. The last time through the loop, it will be set to 0 .

forloop.revcounter0 绫讳技浜 forloop.revcounter 锛屼絾瀹冧互0鍋氫负缁撴潫绱㈠紩銆傚湪绗竴娆℃墽琛屽惊鐜椂锛岃鍙橀噺浼氳缃负搴忓垪鐨勯」鐨勪釜鏁板噺1銆傚湪鏈鍚庝竴娆¤凯浠f椂锛岃鍙橀噺涓0銆

forloop.first is a Boolean value set to True if this is the first time through the loop. This is convenient for special casing:

forloop.first 鏄竴涓竷灏斿笺傚湪绗竴娆℃墽琛屽惊鐜椂璇ュ彉閲忎负True锛屽湪涓嬮潰鐨勬儏褰腑杩欎釜鍙橀噺鏄緢鏈夌敤鐨勩

{% for object in objects %}
    {% if forloop.first %}<li class="first">{% else %}<li>{% endif %}
    {{ object }}
    </li>
{% endfor %}

forloop.last is a Boolean value set to True if this is the last time through the loop. A common use for this is to put pipe characters between a list of links:

forloop.last 鏄竴涓竷灏斿硷紱鍦ㄦ渶鍚庝竴娆℃墽琛屽惊鐜椂琚疆涓篢rue銆備竴涓父瑙佺殑鐢ㄦ硶鏄湪涓绯诲垪鐨勯摼鎺ヤ箣闂存斁缃閬撶锛坾锛

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

The above template code might output something like this::

        Link1 | Link2 | Link3 | Link4

forloop.parentloop is a reference to the forloop object for the parent loop, in case of nested loops. Heres an example:

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

The magic forloop variable is only available within loops. After the template parser has reached {% endfor %} , forloop disappears.

forloop 鍙橀噺浠呬粎鑳藉鍦ㄥ惊鐜腑浣跨敤锛屽湪妯℃澘瑙f瀽鍣ㄧ鍒 {% endfor %} 鏍囩鏃讹紝 forloop 灏变笉鍙闂簡銆

Context and the forloop Variable

Context鍜宖orloop鍙橀噺

Inside the {% for %} block, the existing variables are moved out of the way to avoid overwriting the magic forloop variable. Django exposes this moved context in forloop.parentloop . You generally dont need to worry about this, but if you supply a template variable named forloop (though we advise against it), it will be named forloop.parentloop while inside the {% for %} block.

鍦ㄤ竴涓 {% for %} 鍧椾腑锛屽凡瀛樺湪鐨勫彉閲忎細琚Щ闄わ紝浠ラ伩鍏 forloop 鍙橀噺琚鐩栥侱jango浼氭妸杩欎釜鍙橀噺绉诲姩鍒 forloop.parentloop 涓傞氬父鎴戜滑涓嶇敤鎷呭績杩欎釜闂锛屼絾鏄竴鏃︽垜浠湪妯℃澘涓畾涔変簡 forloop 杩欎釜鍙橀噺锛堝綋鐒舵垜浠弽瀵硅繖鏍峰仛锛夛紝鍦 {% for %} 鍧椾腑瀹冧細鍦 forloop.parentloop 琚噸鏂板懡鍚嶃

ifequal/ifnotequal
ifequal/ifnotequal

The Django template system deliberately is not a full-fledged programming language and thus does not allow you to execute arbitrary Python statements. (More on this idea in the section Philosophies and Limitations.) However, its quite a common template requirement to compare two values and display something if theyre equaland Django provides an {% ifequal %} tag for that purpose.

Django妯℃澘绯荤粺鍘嬫牴鍎垮氨娌℃兂杩囧疄鐜颁竴涓叏鍔熻兘鐨勭紪绋嬭瑷锛屾墍浠ュ畠涓嶅厑璁告垜浠湪妯℃澘涓墽琛孭ython鐨勮鍙ワ紙杩樻槸閭e彞璇濓紝瑕佷簡瑙f洿澶氳鍙傜湅鐞嗗康鍜岄檺鍒跺皬鑺傦級銆備絾鏄瘮杈冧袱涓彉閲忕殑鍊煎苟涓旀樉绀轰竴浜涚粨鏋滃疄鍦ㄦ槸涓お甯歌鐨勯渶姹備簡锛屾墍浠jango鎻愪緵浜 {% ifequal %} 鏍囩渚涙垜浠娇鐢ㄣ

The {% ifequal %} tag compares two values and displays everything between {% ifequal %} and {% endifequal %} if the values are equal.

{% ifequal %} 鏍囩姣旇緝涓や釜鍊硷紝褰撲粬浠浉鍚屾椂锛屾樉绀哄湪 {% ifequal %}{% endifequal %} 涔嬩腑鎵鏈夌殑鍊笺

This example compares the template variables user and currentuser :

涓嬮潰鐨勪緥瀛愭瘮杈冧袱涓ā鏉垮彉閲 usercurrentuser :

{% ifequal user currentuser %}
    <h1>Welcome!</h1>
{% endifequal %}

The arguments can be hard-coded strings, with either single or double quotes, so the following is valid:

鍙傛暟鍙互鏄‖缂栫爜鐨勫瓧绗︿覆锛岄殢渚跨敤鍗曞紩鍙锋垨鑰呭弻寮曞彿寮曡捣鏉ワ紝鎵浠ヤ笅鍒椾唬鐮侀兘鏄纭殑锛

{% ifequal section 'sitenews' %}
    <h1>Site News</h1>
{% endifequal %}

{% ifequal section "community" %}
    <h1>Community</h1>
{% endifequal %}

Just like {% if %} , the {% ifequal %} tag supports an optional {% else %} :

{% if %} 绫讳技锛 {% ifequal %} 鏀寔鍙夌殑 {% else%} 鏍囩锛

{% ifequal section 'sitenews' %}
    <h1>Site News</h1>
{% else %}
    <h1>No News Here</h1>
{% endifequal %}

Only template variables, strings, integers, and decimal numbers are allowed as arguments to {% ifequal %} . These are valid examples:

鍙湁妯℃澘鍙橀噺锛屽瓧绗︿覆锛屾暣鏁板拰灏忔暟鍙互浣滀负 {% ifequal %} 鏍囩鐨勫弬鏁般傝繖浜涙槸姝g‘鐨勪緥瀛愶細

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

Any other types of variables, such as Python dictionaries, lists, or Booleans, cant be hard-coded in {% ifequal %} . These are invalid examples:

鍏朵粬鐨勪竴浜涚被鍨嬶紝渚嬪Python鐨勫瓧鍏哥被鍨嬨佸垪琛ㄧ被鍨嬨佸竷灏旂被鍨嬶紝涓嶈兘鐢ㄥ湪 {% ifequal %} 涓 涓嬮潰鏄簺閿欒鐨勪緥瀛愶細

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

If you need to test whether something is true or false, use the {% if %} tags instead of {% ifequal %} .

濡傛灉浣犻渶瑕佸垽鏂彉閲忔槸鐪熻繕鏄亣锛岃浣跨敤 {% if %} 鏉ユ浛浠 {% ifequal %}

Comments
娉ㄩ噴

Just as in HTML or in a programming language such as Python, the Django template language allows for comments. To designate a comment, use {# #} :

璞TML鍜屽叾浠栫殑璇█渚嬪python涓鏍凤紝Django妯℃澘绯荤粺涔熷厑璁告敞閲娿 娉ㄩ噴浣跨敤 {# #}

{# This is a comment #}

The comment will not be output when the template is rendered.

娉ㄩ噴鐨勫唴瀹逛笉浼氬湪妯℃澘娓叉煋鏃惰緭鍑恒

A comment cannot span multiple lines. This limitation improves template parsing performance. In the following template, the rendered output will look exactly the same as the template (i.e., the comment tag will not be parsed as a comment):

娉ㄩ噴涓嶈兘璺ㄥ琛屻傝繖涓檺鍒舵槸涓轰簡鎻愰珮妯℃澘瑙f瀽鐨勬ц兘銆傚湪涓嬮潰杩欎釜妯℃澘涓紝杈撳嚭缁撴灉鍜屾ā鏉挎湰韬槸 瀹屽叏涓鏍风殑锛堜篃灏辨槸璇达紝娉ㄩ噴鏍囩骞舵病鏈夎瑙f瀽涓烘敞閲婏級锛

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

Filters

杩囨护鍣

As explained earlier in this chapter, template filters are simple ways of altering the value of variables before theyre displayed. Filters look like this:

灏辫薄鏈珷鍓嶉潰鎻愬埌鐨勪竴鏍凤紝妯℃澘杩囨护鍣ㄦ槸鍦ㄥ彉閲忚鏄剧ず鍓嶄慨鏀瑰畠鐨勫肩殑涓涓畝鍗曟柟娉曘 杩囨护鍣ㄧ湅璧锋潵鏄繖鏍风殑锛

{{ name|lower }}

This displays the value of the {{ name }} variable after being filtered through the lower filter, which converts text to lowercase. Use a pipe (| ) to apply a filter.

鏄剧ず鐨勫唴瀹规槸鍙橀噺 {{ name }} 琚繃婊ゅ櫒 lower 澶勭悊鍚庣殑缁撴灉锛屽畠鍔熻兘鏄浆鎹㈡枃鏈负灏忓啓銆 浣跨敤 | 鏉ュ簲鐢ㄨ繃婊ゅ櫒銆

Filters can be chained that is, the output of one filter is applied to the next. Heres a common idiom for escaping text contents, and then converting line breaks to <p> tags:

杩囨护鍣ㄥ彲浠ヨ 涓茶仈 ,灏辨槸璇翠竴涓繃婊ゅ櫒鐨勮緭鍑哄彲浠ヨ杈撳叆鍒颁笅涓涓繃婊ゅ櫒銆傝繖閲屾湁涓涓父鐢ㄧ殑 闇姹傦紝鍏堣浆涔夋枃鏈埌HTML锛屽啀杞崲姣忚鍒 <p> 鏍囩锛

{{ my_text|escape|linebreaks }}

Some filters take arguments. A filter argument looks like this:

鏈変簺杩囨护鍣ㄦ湁鍙傛暟銆傝繃婊ゅ櫒鍙傛暟鐪嬭捣鏉ユ槸杩欐牱鐨勶細

{{ bio|truncatewords:"30" }}

This displays the first 30 words of the bio variable. Filter arguments are always in double quotes.

杩欎釜灏嗘樉绀哄彉閲 bio 鐨勫墠30涓瘝銆傝繃婊ゅ櫒鍙傛暟鎬绘槸浣跨敤鍙屽紩鍙锋爣璇嗐

The following are a few of the most important filters; Appendix F covers the rest.

涓嬮潰鏄竴浜涙渶閲嶈鐨勮繃婊ゅ櫒锛涢檮褰旻鏈夊畬鏁寸殑杩囨护鍣ㄥ垪琛ㄣ

addslashes : Adds a backslash before any backslash, single quote, or double quote. This is useful if the produced text is included in a JavaScript string.

addslashes : 娣诲姞鍙嶆枩鏉犲埌浠讳綍鍙嶆枩鏉犮佸崟寮曞彿鎴栬呭弻寮曞彿鍓嶉潰銆 杩欏湪澶勭悊鍖呭惈JavaScript鐨勬枃鏈椂鏄潪甯告湁鐢ㄧ殑銆

date : Formats a date or datetime object according to a format string given in the parameter, for example:

date : 鎸夋寚瀹氱殑鏍煎紡瀛楃涓插弬鏁版牸寮忓寲 date 鎴栬 datetime 瀵硅薄锛 鑼冧緥锛

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

Format strings are defined in Appendix F.

鏍煎紡鍙傛暟鐨勫畾涔夊湪闄勫綍F涓

escape : Escapes ampersands, quotes, and angle brackets in the given string. This is useful for sanitizing user-submitted data and for ensuring data is valid XML or XHTML. Specifically, escape makes these conversions:

escape : 杞箟 &绗﹀彿锛屽紩鍙凤紝<锛> 绗﹀彿銆 杩欏湪纭繚鐢ㄦ埛鎻愪氦鐨勬暟鎹槸鏈夋晥鐨刋ML鎴朮HTML鏃舵槸闈炲父鏈夌敤鐨勩 鍏蜂綋涓婏紝 escape 鍋氫笅闈㈣繖浜涜浆鎹:

  • Converts & to &amp;

escape : 杞箟 &绗﹀彿锛屽紩鍙凤紝<锛> 绗﹀彿銆 杩欏湪纭繚鐢ㄦ埛鎻愪氦鐨勬暟鎹槸鏈夋晥鐨刋ML鎴朮HTML鏃舵槸闈炲父鏈夌敤鐨勩 鍏蜂綋涓婏紝 escape 鍋氫笅闈㈣繖浜涜浆鎹:

  • Converts < to &lt;

  • 杞崲 <&lt;

  • Converts > to &gt;

  • 杞崲 >&gt;

  • Converts " (double quote) to &quot;

  • 杞崲 " (鍙屽紩鍙) 鍒 &quot;

  • Converts ' (single quote) to &#39;

  • 杞崲 ' (鍗曞紩鍙) 鍒 &#39;

length : Returns the length of the value. You can use this on a list or a string, or any Python object that knows how to determine its length (i.e., any object that has a __len__() method).

length : 杩斿洖鍙橀噺鐨勯暱搴︺備綘鍙互瀵瑰垪琛ㄦ垨鑰呭瓧绗︿覆锛屾垨鑰呬换浣曠煡閬撴庝箞娴嬪畾闀垮害鐨凱ython 瀵硅薄浣跨敤杩欎釜鏂规硶锛堜篃灏辨槸璇达紝鏈 __len__() 鏂规硶鐨勫璞★級銆

Philosophies and Limitations

鐞嗗康涓庡眬闄

Now that youve gotten a feel for the Django template language, we should point out some of its intentional limitations, along with some philosophies behind why it works the way it works.

鐜板湪浣犲凡缁忓Django鐨勬ā鏉胯瑷鏈変竴浜涜璇嗕簡锛屾垜浠皢鎸囧嚭涓浜涚壒鎰忚缃殑闄愬埗鍜屼负浠涔堣杩欐牱鍋 鑳屽悗鐨勪竴浜涜璁″摬瀛︺

More than any other component of Web applications, programmer opinions on template systems vary wildly. The fact that Python alone has dozens, if not hundreds, of open source template-language implementations supports this point. Each was likely created because its developer deemed all existing template languages inadequate. (In fact, it is said to be a rite of passage for a Python developer to write his or her own template language! If you havent done this yet, consider it. Its a fun exercise.)

鐩稿Web搴旂敤涓殑鍏朵粬缁勪欢锛岀▼搴忓憳浠妯℃澘绯荤粺鐨勫垎姝ф槸鏈澶х殑銆備簨瀹炰笂锛孭ython鏈夋垚鍗佷笂鐧剧殑 寮鏀炬簮鐮佺殑妯℃澘璇█瀹炵幇銆傛瘡涓疄鐜伴兘鏄洜涓哄紑鍙戣呰涓虹幇瀛樼殑妯℃澘璇█涓嶅鐢ㄣ傦紙浜嬪疄涓婏紝瀵逛竴涓 Python寮鍙戣呮潵璇达紝鍐欎竴涓嚜宸辩殑妯℃澘璇█灏辫薄鏄煇绉嶁滄垚浜虹ぜ鈥濅竴鏍凤紒濡傛灉浣犺繕娌℃湁瀹屾垚涓涓嚜宸辩殑 妯℃澘璇█锛屽ソ濂借冭檻鍐欎竴涓紝杩欐槸涓涓潪甯告湁瓒g殑閿荤偧銆傦級

With that in mind, you might be interested to know that Django doesnt require that you use its template language. Because Django is intended to be a full-stack Web framework that provides all the pieces necessary for Web developers to be productive, many times its more convenient to use Djangos template system than other Python template libraries, but its not a strict requirement in any sense. As youll see in the upcoming section Using Templates in Views, its very easy to use another template language with Django.

鏄庣櫧浜嗚繖涓紝浣犱篃璁告湁鍏磋叮鐭ラ亾浜嬪疄涓奃jango骞朵笉寮哄埗瑕佹眰浣犲繀椤讳娇鐢ㄥ畠鐨勬ā鏉胯瑷銆傚洜涓篋jango 铏界劧琚璁℃垚涓涓狥ULL-Stack鐨刉eb妗嗘灦锛屽畠鎻愪緵浜嗗紑鍙戣呮墍蹇呴渶鐨勬墍鏈夌粍浠讹紝鑰屼笖鍦ㄥぇ澶氭暟鎯呭喌 浣跨敤Django妯℃澘绯荤粺浼氭瘮鍏朵粬鐨凱ython妯℃澘搴撹 鏇存柟渚 涓鐐癸紝浣嗘槸骞朵笉鏄弗鏍艰姹備綘蹇呴』浣跨敤 瀹冦傚氨璞′綘灏嗗湪鍚庣画鐨勭珷鑺備腑鐪嬪埌鐨勪竴鏍凤紝浣犱篃鍙互闈炲父瀹规槗鐨勫湪Django涓娇鐢ㄥ叾浠栫殑妯℃澘璇█銆

Still, its clear we have a strong preference for the way Djangos template language works. The template system has roots in how Web development is done at World Online and the combined experience of Djangos creators. Here are a few of those philosophies:

铏界劧濡傛锛屽緢鏄庢樉锛屾垜浠Django妯℃澘璇█鐨勫伐浣滄柟寮忔湁鐫寮虹儓鐨勫亸鐖便傝繖涓ā鏉胯瑷鏉ユ簮浜嶹orld Online鐨勫紑鍙戠粡楠屽拰Django鍒涢犺呬滑闆嗕綋鏅烘収鐨勭粨鏅躲備笅闈㈡槸鍏充簬瀹冪殑涓浜涜璁″摬瀛︾悊蹇碉細

Business logic should be separated from presentation logic . We see a template system as a tool that controls presentation and presentation-related logicand thats it. The template system shouldnt support functionality that goes beyond this basic goal.

涓氬姟閫昏緫搴旇鍜岃〃鐜伴昏緫鐩稿鍒嗗紑 銆傛垜浠皢妯℃澘绯荤粺瑙嗕负鎺у埗琛ㄧ幇鍙婅〃鐜扮浉鍏抽昏緫鐨勫伐鍏凤紝浠呮鑰屽凡銆傛ā鏉跨郴缁熶笉搴旀彁渚涜秴鍑烘鍩烘湰鐩爣鐨勫姛鑳姐

For that reason, its impossible to call Python code directly within Django templates. All programming is fundamentally limited to the scope of what template tags can do. It is possible to write custom template tags that do arbitrary things, but the out-of-the-box Django template tags intentionally do not allow for arbitrary Python code execution.

鍑轰簬杩欎釜鍘熷洜锛屽湪 Django 妯℃澘涓槸涓嶅彲鑳界洿鎺ヨ皟鐢 Python 浠g爜鐨勩傛墍鏈夌殑缂栫▼宸ヤ綔鍩烘湰涓婇兘琚眬闄愪簬妯℃澘鏍囩鐨勮兘鍔涜寖鍥淬傚綋鐒讹紝 鏈夊彲鑳藉啓鍑鸿嚜瀹氫箟鐨勬ā鏉挎爣绛炬潵瀹屾垚浠绘剰宸ヤ綔锛屼絾杩欎簺鈥滆秴鑼冨洿鈥濈殑 Django 妯℃澘鏍囩鏈夋剰鍦颁笉鍏佽鎵ц浠讳綍 Python 浠g爜銆

Syntax should be decoupled from HTML/XML . Although Djangos template system is used primarily to produce HTML, its intended to be just as usable for non-HTML formats, such as plain text. Some other template languages are XML based, placing all template logic within XML tags or attributes, but Django deliberately avoids this limitation. Requiring valid XML to write templates introduces a world of human mistakes and hard-to-understand error messages, and using an XML engine to parse templates incurs an unacceptable level of overhead in template processing.

璇硶涓嶅簲鍙楀埌 HTML/XML 鐨勬潫缂 銆傚敖绠 Django 妯℃澘绯荤粺涓昏鐢ㄤ簬鐢熸垚 HTML锛屽畠杩樻槸琚湁鎰忓湴璁捐涓哄彲鐢熸垚闈 HTML 鏍煎紡锛屽绾枃鏈備竴浜涘叾瀹冪殑妯℃澘璇█鏄熀浜 XML 鐨勶紝灏嗘墍鏈夌殑妯℃澘閫昏緫缃簬 XML 鏍囩涓庡睘鎬т箣涓紝鑰 Django 鏈夋剰鍦伴伩寮浜嗚繖绉嶉檺鍒躲傚己鍒惰姹備娇鐢ㄦ湁鏁 XML 缂栧啓妯℃澘灏嗕細寮曞彂澶ч噺鐨勪汉涓洪敊璇拰闅句互鐞嗚В鐨勯敊璇俊鎭紝鑰屼笖浣跨敤 XML 寮曟搸瑙f瀽妯℃澘涔熶細瀵艰嚧浠や汉鏃犳硶瀹瑰繊鐨勬ā鏉垮鐞嗗紑閿銆

Designers are assumed to be comfortable with HTML code . The template system isnt designed so that templates necessarily are displayed nicely in WYSIWYG editors such as Dreamweaver. That is too severe a limitation and wouldnt allow the syntax to be as nice as it is. Django expects template authors to be comfortable editing HTML directly.

鍋囧畾璁捐甯堢簿閫 HTML 缂栫爜 銆傛ā鏉跨郴缁熺殑璁捐鎰忓浘骞朵笉鏄负浜嗚妯℃澘涓瀹氳兘澶熷緢濂藉湴鏄剧ず鍦 Dreamweaver 杩欐牱鐨勬墍瑙佸嵆鎵寰楃紪杈戝櫒涓傝繖绉嶉檺鍒惰繃浜庤嫑鍒伙紝鑰屼笖浼氫娇寰楄娉曚笉鑳藉儚鐩墠杩欐牱鐨勫畬缇庛侱jango 瑕佹眰妯℃澘鍒涗綔浜哄憳瀵圭洿鎺ョ紪杈 HTML 闈炲父鐔熸倝銆

Designers are assumed not to be Python programmers . The template system authors recognize that Web page templates are most often written by designers , not programmers , and therefore should not assume Python knowledge.

鍋囧畾璁捐甯堜笉鏄 Python 绋嬪簭鍛 銆傛ā鏉跨郴缁熷紑鍙戜汉鍛樿涓猴細缃戦〉妯℃澘閫氬父鐢 璁捐甯 鑰屼笉鏄 绋嬪簭鍛 缂栧啓锛屽洜鑰屽亣瀹氳繖浜涗汉骞朵笉鎺屾彙 Python 鐩稿叧鐭ヨ瘑銆

However, the system also intends to accommodate small teams in which the templates are created by Python programmers. It offers a way to extend the systems syntax by writing raw Python code. (More on this in Chapter 10.)

褰撶劧锛岀郴缁熷悓鏍蜂篃鐗规剰鍦版彁渚涗簡瀵归偅浜 Python 绋嬪簭鍛樿繘琛屾ā鏉垮埗浣滅殑灏忓瀷鍥㈤槦鐨勬敮鎸併傚畠鎻愪緵浜嗕竴绉嶅伐浣滄ā寮忥紝鍏佽閫氳繃缂栧啓鍘熺敓 Python 浠g爜杩涜绯荤粺璇硶鎷撳睍銆傦紙璇﹁绗崄绔狅級

The goal is not to invent a programming language . The goal is to offer just enough programming-esque functionality, such as branching and looping, that is essential for making presentation-related decisions.

鐩爣骞朵笉鏄鍙戞槑涓绉嶇紪绋嬭瑷 銆傜洰鏍囨槸鎭板埌濂藉鍦版彁渚涘鍒嗘敮鍜屽惊鐜繖涓绫荤紪绋嬪紡鍔熻兘锛岃繖鏄繘琛屼笌琛ㄧ幇鐩稿叧鍒ゆ柇鐨勫熀纭銆

As a result of these design philosophies, the Django template language has the following limitations:

閲囩敤杩欎簺璁捐鐞嗗康鐨勭粨鏋滄槸瀵艰嚧 Django 妯℃澘璇█鏈変互涓嬪嚑鐐归檺鍒讹細

  • A template cannot set a variable or change the value of a variable . Its possible to write custom template tags that accomplish these goals (see Chapter 10), but the stock Django template tags do not allow it.

  • 妯℃澘涓笉鑳借缃彉閲忓拰鏀瑰彉鍙橀噺鐨勫 銆傚彲浠ラ氳繃缂栧啓鑷畾涔夋ā鏉挎爣绛惧仛鍒拌繖涓鐐癸紙鍙傝绗崄绔狅級锛屼絾姝e畻鐨 Django 妯℃澘鏍囩鍋氫笉鍒般

  • A template cannot call raw Python code . Theres no way to drop into Python mode or use raw Python constructs. Again, its possible to write custom template tags to do this, but the stock Django template tags dont allow it.

  • 妯℃澘涓笉鑳借皟鐢ㄤ换浣曠殑Python浠g爜 銆備笉瀛樺湪杞叆 Python 妯″紡鎴栦娇鐢ㄥ師鐢 Python 鏁版嵁缁撴瀯鐨勬柟娉曘傚拰鍓嶉潰涓鏍凤紝鍙互缂栧啓鑷畾涔夋ā鏉挎爣绛炬潵瀹炵幇杩欎釜鐩爣锛屼絾姝g当鐨 Django 妯℃澘鏍囩鍋氫笉鍒般

Using Templates in Views

鍦ㄨ鍥句腑浣跨敤妯℃澘

Youve learned the basics of using the template system; now lets use this knowledge to create a view. Recall the current_datetime view in mysite.views , which we started in the previous chapter. Heres what it looks like:

鍦ㄥ涔犱簡妯℃澘绯荤粺鐨勫熀纭涔嬪悗锛岀幇鍦ㄨ鎴戜滑浣跨敤鐩稿叧鐭ヨ瘑鏉ュ垱寤鸿鍥俱傞噸鏂版墦寮鎴戜滑鍦ㄥ墠涓绔犲湪 mysite.views 涓垱寤虹殑 current_datetime 瑙嗗浘銆備互涓嬫槸鍏跺唴瀹癸細

from django.http import HttpResponse
import datetime

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

Lets change this view to use Djangos template system. At first, you might think to do something like this:

璁╂垜浠敤 Django 妯℃澘绯荤粺鏉ヤ慨鏀硅瑙嗗浘銆傜涓姝ワ紝浣犲彲鑳藉凡缁忔兂鍒颁簡瑕佸仛涓嬮潰杩欐牱鐨勪慨鏀癸細

from django.template import Template, Context
from django.http import HttpResponse
import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    t = Template("<html><body>It is now {{ current_date }}.</body></html>")
    html = t.render(Context({'current_date': now}))
    return HttpResponse(html)

Sure, that uses the template system, but it doesnt solve the problems we pointed out in the introduction of this chapter. Namely, the template is still embedded in the Python code. Lets fix that by putting the template in a separate file , which this view will load.

娌¢敊锛屽畠纭疄浣跨敤浜嗘ā鏉跨郴缁燂紝浣嗘槸骞舵病鏈夎В鍐虫垜浠湪鏈珷寮澶存墍鎸囧嚭鐨勯棶棰樸備篃灏辨槸璇达紝妯℃澘渚濈劧鍐呭祵鍦 Python 浠g爜涔嬩腑銆傝鎴戜滑灏嗘ā鏉跨疆浜庝竴涓 鍗曠嫭鐨勬枃浠 涓紝骞朵笖璁╄鍥惧姞杞借鏂囦欢鏉ヨВ鍐虫闂銆

You might first consider saving your template somewhere on your filesystem and using Pythons built-in file-opening functionality to read the contents of the template. Heres what that might look like, assuming the template was saved as the file /home/djangouser/templates/mytemplate.html :

浣犲彲鑳介鍏堣冭檻鎶婃ā鏉夸繚瀛樺湪鏂囦欢绯荤粺鐨勬煇涓綅缃苟鐢 Python 鍐呭缓鐨勬枃浠舵搷浣滃嚱鏁版潵璇诲彇鏂囦欢鍐呭銆傚亣璁炬枃浠朵繚瀛樺湪 /home/djangouser/templates/mytemplate.html 涓殑璇濓紝浠g爜灏变細鍍忎笅闈㈣繖鏍:

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

This approach, however, is inelegant for these reasons:

鐒惰岋紝鍩轰簬浠ヤ笅鍑犱釜鍘熷洜锛岃鏂规硶杩樼畻涓嶄笂绠娲侊細

  • It doesnt handle the case of a missing file. If the file mytemplate.html doesnt exist or isnt readable, the open() call will raise an IOError exception.

  • 瀹冩病鏈夊鏂囦欢涓㈠け鐨勬儏鍐靛仛鍑哄鐞嗐傚鏋滄枃浠 mytemplate.html 涓嶅瓨鍦ㄦ垨鑰呬笉鍙锛 open() 鍑芥暟璋冪敤灏嗕細寮曞彂 IOError 寮傚父銆

  • It hard-codes your template location. If you were to use this technique for every view function, youd be duplicating the template locations. Not to mention it involves a lot of typing!

  • 杩欓噷瀵规ā鏉挎枃浠剁殑浣嶇疆杩涜浜嗙‖缂栫爜銆傚鏋滀綘鍦ㄦ瘡涓鍥惧嚱鏁伴兘鐢ㄨ鎶鏈紝灏辫涓嶆柇澶嶅埗杩欎簺妯℃澘鐨勪綅缃傛洿涓嶇敤璇磋繕瑕佸甫鏉ュぇ閲忕殑杈撳叆宸ヤ綔锛

  • It includes a lot of boring boilerplate code. Youve got better things to do than to write calls to open() , fp.read() , and fp.close() each time you load a template.

  • 瀹冨寘鍚簡澶ч噺浠や汉鐢熷帉鐨勯噸澶嶄唬鐮併備笌鍏跺湪姣忔鍔犺浇妯℃澘鏃堕兘璋冪敤 open()fp.read()fp.close() 锛岃繕涓嶅鍋氬嚭鏇翠匠閫夋嫨銆

To solve these issues, well use template loading and template directories , both of which are described in the sections that follow.

瑕佽В鍐虫闂锛屾垜浠皢浣跨敤 妯℃澘鍔犺浇妯℃澘鐩綍 锛岃繖鏄垜浠湪鎺ヤ笅鏉ョ殑绔犺妭涓璁ㄨ鐨勪袱涓瘽棰樸

Template Loading

妯℃澘鍔犺浇

Django provides a convenient and powerful API for loading templates from disk, with the goal of removing redundancy both in your template-loading calls and in your templates themselves.

涓轰簡鍑忓皯妯℃澘鍔犺浇璋冪敤杩囩▼鍙婃ā鏉挎湰韬殑鍐椾綑浠g爜锛孌jango 鎻愪緵浜嗕竴绉嶄娇鐢ㄦ柟渚夸笖鍔熻兘寮哄ぇ鐨 API 锛岀敤浜庝粠纾佺洏涓姞杞芥ā鏉匡紝

In order to use this template-loading API, first youll need to tell the framework where you store your templates. The place to do this is in your settings file .

瑕佷娇鐢ㄦ妯℃澘鍔犺浇API锛岄鍏堜綘蹇呴』灏嗘ā鏉跨殑淇濆瓨浣嶇疆鍛婅瘔妗嗘灦銆傝椤瑰伐浣滃湪 璁剧疆鏂囦欢 涓畬鎴愩

A Django settings file is the place to put configuration for your Django instance (aka your Django project). Its a simple Python module with module-level variables, one for each setting.

Django 璁剧疆鏂囦欢鏄瓨鏀 Django 瀹炰緥锛堜篃灏辨槸 Django 椤圭洰锛夐厤缃殑鍦版柟銆傚畠鏄竴涓畝鍗曠殑 Python 妯″潡锛屽叾涓寘鍚簡涓浜涙ā鍧楃骇鍙橀噺锛屾瘡涓兘鏄竴椤硅缃

When you ran django-admin.py startproject mysite in Chapter 2, the script created a default settings file for you, aptly named settings.py . Have a look at the files contents. It contains variables that look like this (though not necessarily in this order):

绗簩绔犱腑鎵ц django-admin.py startproject mysite 鍛戒护鏃讹紝瀹冧负浣犲垱寤轰簡涓涓殑缂虹渷閰嶇疆鏂囦欢锛屽苟鎭板鍏跺垎鍦板皢鍏跺悕涓 settings.py 銆傛煡鐪嬩竴涓嬭鏂囦欢鍐呭銆傚叾涓寘鍚涓嬪彉閲忥紙浣嗗苟涓嶄竴瀹氭槸杩欎釜椤哄簭锛夛細

DEBUG = True
TIME_ZONE = 'America/Chicago'
USE_I18N = True
ROOT_URLCONF = 'mysite.urls'

This is pretty self-explanatory; the settings and their respective values are simple Python variables. And because the settings file is just a plain Python module, you can do dynamic things such as checking the value of one variable before setting another. (This also means that you should avoid Python syntax errors in your settings file.)

杩欓噷鏃犻渶鏇村璇犻噴锛涜缃」涓庡煎潎涓虹畝鍗曠殑 Python 鍙橀噺銆傚悓鏃剁敱浜庨厤缃枃浠跺彧涓嶈繃鏄函 Python 妯″潡锛屼綘鍙互瀹屾垚涓浜涘姩鎬佸伐浣滐紝姣斿鍦ㄨ缃煇鍙橀噺涔嬪墠妫鏌ュ彟涓鍙橀噺鐨勫笺傦紙杩欎篃鎰忓懗鐫浣犲繀椤婚伩鍏嶉厤缃枃浠跺嚭鐜 Python 璇硶閿欒銆傦級

Well cover settings files in depth in Appendix E, but for now, have a look at the TEMPLATE_DIRS setting. This setting tells Djangos template-loading mechanism where to look for templates. By default, its an empty tuple. Pick a directory where youd like to store your templates and add it to TEMPLATE_DIRS , like so:

鎴戜滑灏嗗湪闄勫綍 E 涓杩伴厤缃枃浠讹紝鐩墠鑰岃█锛屼粎闇鍏虫敞 TEMPLATE_DIRS 璁剧疆銆傝璁剧疆鍛婅瘔 Django 鐨勬ā鏉垮姞杞芥満鍒跺湪鍝噷鏌ユ壘妯℃澘銆傜己鐪佹儏鍐典笅锛岃璁剧疆鐨勫兼槸涓涓┖鐨勫厓缁勩傞夋嫨涓涓洰褰曠敤浜庡瓨鏀炬ā鏉垮苟灏嗗叾娣诲姞鍒 TEMPLATE_DIRS 涓細

TEMPLATE_DIRS = (
    '/home/django/mysite/templates',
)

There are a few things to note:

涓嬮潰鏄竴浜涙敞鎰忎簨椤癸細

You can specify any directory you want, as long as the directory and templates within that directory are readable by the user account under which your Web server runs. If you cant think of an appropriate place to put your templates, we recommend creating a templates directory within your Django project (i.e., within the mysite directory you created in Chapter 2, if youve been following along with this books examples).

浣犲彲浠ヤ换鎰忔寚瀹氭兂瑕佺殑鐩綍锛屽彧瑕佽繍琛 Web 鏈嶅姟鍣ㄧ殑鐢ㄦ埛璐﹀彿鍙互璇诲彇璇ョ洰褰曠殑瀛愮洰褰曞拰妯℃澘鏂囦欢銆傚鏋滃疄鍦ㄦ兂涓嶅嚭鍚堥傜殑浣嶇疆鏉ユ斁缃ā鏉匡紝鎴戜滑寤鸿鍦 Django 椤圭洰涓垱寤轰竴涓 templates 鐩綍锛堜篃灏辨槸璇达紝濡傛灉浣犱竴鐩撮兘鎸夋湰涔︾殑鑼冧緥鎿嶄綔鐨勮瘽锛屽湪绗簩绔犲垱寤虹殑 mysite 鐩綍涓級銆

Dont forget the comma at the end of the template directory string! Python requires commas within single-element tuples to disambiguate the tuple from a parenthetical expression. This is a common newbie gotcha.

涓嶈蹇樿妯℃澘鐩綍瀛楃涓插熬閮ㄧ殑閫楀彿锛丳ython 瑕佹眰鍗曞厓绱犲厓缁勪腑蹇呴』浣跨敤閫楀彿锛屼互姝ゆ秷闄や笌鍦嗘嫭鍙疯〃杈惧紡涔嬮棿鐨勬涔夈傝繖鏄柊鎵嬪父鐘殑閿欒銆

If you want to avoid this error, you can make TEMPLATE_DIRS a list instead of a tuple, because single-element lists dont require a trailing comma:

鎯抽伩鍏嶆閿欒鐨勮瘽锛屼綘鍙互灏嗗垪琛ㄨ屼笉鏄厓缁勭敤浣 TEMPLATE_DIRS 锛屽洜涓哄崟鍏冪礌鍒楄〃骞朵笉寮哄埗瑕佹眰浠ラ楀彿鏀跺熬锛

TEMPLATE_DIRS = [
    '/home/django/mysite/templates'
]

A tuple is slightly more semantically correct than a list (tuples cannot be changed after being created, and nothing should be changing settings once theyve been read), so we recommend using a tuple for your TEMPLATE_DIRS setting.

浠庤涔変笂鐪嬶紝鍏冪粍姣斿垪琛ㄧ暐鏄惧悎閫傦紙鍏冪粍鍦ㄥ垱寤轰箣鍚庡氨涓嶈兘淇敼锛岃岄厤缃璇诲彇浠ュ悗灏变笉搴旇鏈変换浣曚慨鏀癸級銆傚洜姝わ紝鎴戜滑鎺ㄨ崘瀵 TEMPLATE_DIRS 璁剧疆浣跨敤鍏冪粍銆

If youre on Windows, include your drive letter and use Unix-style forward slashes rather than backslashes, as follows:

濡傛灉浣跨敤鐨勬槸 Windows 骞冲彴锛岃鍖呭惈椹卞姩鍣ㄧ鍙峰苟浣跨敤Unix椋庢牸鐨勬枩鏉狅紙/锛夎屼笉鏄弽鏂滄潬锛圽锛,灏卞儚涓嬮潰杩欐牱锛

TEMPLATE_DIRS = (
    'C:/www/django/templates',
)

Its simplest to use absolute paths (i.e., directory paths that start at the root of the filesystem). If you want to be a bit more flexible and decoupled, though, you can take advantage of the fact that Django settings files are just Python code by constructing the contents of TEMPLATE_DIRS dynamically, for example:

鏈鐪佷簨鐨勬柟寮忔槸浣跨敤缁濆璺緞锛堝嵆浠庢枃浠剁郴缁熸牴鐩綍寮濮嬬殑鐩綍璺緞锛夈傚鏋滄兂瑕佹洿鐏垫椿涓鐐瑰苟鍑忓皯涓浜涜礋闈㈠共鎵帮紝鍙埄鐢 Django 閰嶇疆鏂囦欢灏辨槸 Python 浠g爜杩欎竴鐐规潵鍔ㄦ佹瀯寤 TEMPLATE_DIRS 鐨勫唴瀹癸紝濡傦細

import os.path

TEMPLATE_DIRS = (
    os.path.join(os.path.dirname(__file__), 'templates').replace('\\','/'),
)

This example uses the magic Python variable __file__ , which is automatically set to the file name of the Python module in which the code lives.

杩欎釜渚嬪瓙浣跨敤浜嗙濂囩殑 Python 鍐呴儴鍙橀噺 __file__ 锛岃鍙橀噺琚嚜鍔ㄨ缃负浠g爜鎵鍦ㄧ殑 Python 妯″潡鏂囦欢鍚嶃

With TEMPLATE_DIRS set, the next step is to change the view code to use Djangos template-loading functionality rather than hard-coding the template paths. Returning to our current_datetime view, lets change it like so:

瀹屾垚 TEMPLATE_DIRS 璁剧疆鍚庯紝涓嬩竴姝ュ氨鏄慨鏀硅鍥句唬鐮侊紝璁╁畠浣跨敤 Django 妯℃澘鍔犺浇鍔熻兘鑰屼笉鏄妯℃澘璺緞纭紪鐮併傝繑鍥 current_datetime 瑙嗗浘锛岃繘琛屽涓嬩慨鏀癸細

from django.template.loader import get_template
from django.template import Context
from django.http import HttpResponse
import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    t = get_template('current_datetime.html')
    html = t.render(Context({'current_date': now}))
    return HttpResponse(html)

In this example, were using the function django.template.loader.get_template() rather than loading the template from the filesystem manually. The get_template() function takes a template name as its argument, figures out where the template lives on the filesystem, opens that file, and returns a compiled Template object.

姝よ寖渚嬩腑锛屾垜浠娇鐢ㄤ簡鍑芥暟 django.template.loader.get_template() 锛岃屼笉鏄墜鍔ㄤ粠鏂囦欢绯荤粺鍔犺浇妯℃澘銆傝 get_template() 鍑芥暟浠ユā鏉垮悕绉颁负鍙傛暟锛屽湪鏂囦欢绯荤粺涓壘鍑烘ā鍧楃殑浣嶇疆锛屾墦寮鏂囦欢骞惰繑鍥炰竴涓紪璇戝ソ鐨 Template 瀵硅薄銆

If get_template() cannot find the template with the given name, it raises a TemplateDoesNotExist exception. To see what that looks like, fire up the Django development server again, as in Chapter 3, by running python manage.py runserver within your Django projects directory. Then, point your browser at the page that activates the current_datetime view (e.g., http://127.0.0.1:8000/time/ ). Assuming your DEBUG setting is set to True and you havent yet created a current_datetime.html template, you should see a Django error page highlighting the TemplateDoesNotExist error.

濡傛灉 get_template() 鎵句笉鍒扮粰瀹氬悕绉扮殑妯℃澘锛屽皢浼氬紩鍙戜竴涓 TemplateDoesNotExist 寮傚父銆傝浜嗚В绌剁珶浼氬彂鐢熶粈涔堬紝璁╂垜浠寜鐓х涓夌珷鍐呭锛屽湪 Django 椤圭洰鐩綍涓繍琛 python manage.py runserver 鍛戒护锛屽啀娆″惎鍔―jango寮鍙戞湇鍔″櫒銆傘傜劧鍚庯紝鐢ㄦ祻瑙堝櫒璁块棶椤甸潰锛堝锛 http://127.0.0.1:8000/time/ ) 婵娲 current_datetime 瑙嗗浘銆傚亣濡 DEBUG 璁剧疆涓 True 鑰屽張鏈垱寤 current_datetime.html 妯℃澘锛屼綘灏嗕細鐪嬪埌 TemplateDoesNotExist 閿欒淇℃伅椤甸潰銆

Screenshot of a TemplateDoesNotExist error. Screenshot of a TemplateDoesNotExist error.

Figure 4-1: The error page shown when a template cannot be found.

鍥 4-1: 鏃犳硶鎵惧埌妯℃澘鏃剁殑鍑洪敊椤甸潰

This error page is similar to the one we explained in Chapter 3, with one additional piece of debugging information: a Template-loader postmortem section. This section tells you which templates Django tried to load, along with the reason each attempt failed (e.g., File does not exist). This information is invaluable when youre trying to debug template-loading errors.

璇ラ〉闈笌鎴戜滑鍦ㄧ涓夌珷瑙i噴杩囩殑閿欒椤甸潰鐩镐技锛屽彧涓嶈繃澶氫簡涓鍧楄皟璇曚俊鎭尯锛氭ā鏉垮姞杞藉櫒浜嬪悗妫鏌ュ尯銆傝鍖哄煙鏄剧ず Django 瑕佸姞杞藉摢涓ā鏉裤佹瘡娆″皾璇曞嚭閿欑殑鍘熷洜锛堝锛氭枃浠朵笉瀛樺湪绛夛級銆傚湪璋冭瘯妯℃澘鍔犺浇閿欒鏃讹紝杩欎簺淇℃伅鐨勪环鍊兼槸涓嶅彲浼伴噺鐨勩

As you can probably tell from the error messages found in the Figure 4-1, Django attempted to find the template by combining the directory in the TEMPLATE_DIRS setting with the template name passed to get_template() . So if your TEMPLATE_DIRS contains '/home/django/templates' , Django looks for the file '/home/django/templates/current_datetime.html' . If TEMPLATE_DIRS contains more than one directory, each is checked until the template is found or theyve all been checked.

姝e浣犱粠鍥 4-1 涓殑閿欒淇℃伅涓墍鐪嬪埌锛孌jango 灏濊瘯閫氳繃缁勫悎 TEMPLATE_DIRS 璁剧疆浠ュ強浼犻掔粰 get_template() 鐨勬ā鏉垮悕绉版潵鏌ユ壘妯℃澘銆傚洜姝ゅ鏋 TEMPLATE_DIRS'/home/django/templates' 锛孌jango 灏嗕細 鏌ユ壘 '/home/django/templates/current_datetime.html' 銆傚鏋 TEMPLATE_DIRS 鍖呭惈澶氫釜鐩綍锛屽畠灏嗕細鏌ユ壘姣忎釜鐩綍鐩磋嚦鎵惧埌妯℃澘鎴栨壘閬嶆墍鏈夌洰褰曘

Moving along, create the current_datetime.html file within your template directory using the following template code:

鎺ヤ笅鏉ワ紝鍦ㄦā鏉跨洰褰曚腑鍒涘缓鍖呮嫭浠ヤ笅妯℃澘浠g爜 current_datetime.html 鏂囦欢锛

<html><body>It is now {{ current_date }}.</body></html>

Refresh the page in your Web browser, and you should see the fully rendered page.

鍦ㄧ綉椤垫祻瑙堝櫒涓埛鏂拌椤碉紝浣犲皢浼氱湅鍒板畬鏁磋В鏋愬悗鐨勯〉闈€

render_to_response()

render_to_response()

Because its such a common idiom to load a template, fill a Context , and return an HttpResponse object with the result of the rendered template, Django provides a shortcut that lets you do those things in one line of code. This shortcut is a function called render_to_response() , which lives in the module django.shortcuts . Most of the time, youll be using render_to_response() rather than loading templates and creating Context and HttpResponse objects manually.

鐢变簬鍔犺浇妯℃澘銆佸~鍏 context 銆佸皢缁忚В鏋愮殑妯℃澘缁撴灉杩斿洖涓 HttpResponse 瀵硅薄杩欎竴绯诲垪鎿嶄綔瀹炲湪澶父鐢ㄤ簡锛孌jango 鎻愪緵浜嗕竴鏉′粎鐢ㄤ竴琛屼唬鐮佸氨瀹屾垚鎵鏈夎繖浜涘伐浣滅殑鎹峰緞銆傝鎹峰緞灏辨槸浣嶄簬 django.shortcuts 妯″潡涓悕涓 render_to_response() 鐨勫嚱鏁般傚ぇ澶氭暟鏃跺欙紝浣犲皢浣跨敤 render_to_response() 锛岃屼笉鏄墜鍔ㄥ姞杞芥ā鏉裤佸垱寤 ContextHttpResponse 瀵硅薄銆

Heres the ongoing current_datetime example rewritten to use render_to_response() :

涓嬮潰灏辨槸浣跨敤 render_to_response() 閲嶆柊缂栧啓杩囩殑 current_datetime 鑼冧緥銆

from django.shortcuts import render_to_response
import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    return render_to_response('current_datetime.html', {'current_date': now})

What a difference! Lets step through the code changes:

澶у彉鏍蜂簡锛佽鎴戜滑閫愬彞鐪嬬湅浠g爜鍙戠敓鐨勫彉鍖栵細

  • We no longer have to import get_template , Template , Context , or HttpResponse . Instead, we import django.shortcuts.render_to_response . The import datetime remains.

  • 鎴戜滑涓嶅啀闇瑕佸鍏 get_templateTemplateContextHttpResponse 銆傜浉鍙嶏紝鎴戜滑瀵煎叆 django.shortcuts.render_to_responseimport datetime 缁х画淇濈暀.

  • Within the current_datetime function, we still calculate now , but the template loading, context creation, template rendering, and HttpResponse creation is all taken care of by the render_to_response() call. Because render_to_response() returns an HttpResponse object, we can simply return that value in the view.

  • current_datetime 鍑芥暟涓紝鎴戜滑浠嶇劧杩涜 now 璁$畻锛屼絾妯℃澘鍔犺浇銆佷笂涓嬫枃鍒涘缓銆佹ā鏉胯В鏋愬拰 HttpResponse 鍒涘缓宸ヤ綔鍧囧湪瀵 render_to_response() 鐨勮皟鐢ㄤ腑瀹屾垚浜嗐傜敱浜 render_to_response() 杩斿洖 HttpResponse 瀵硅薄锛屽洜姝ゆ垜浠粎闇鍦ㄨ鍥句腑 return 璇ュ笺

The first argument to render_to_response() should be the name of the template to use. The second argument, if given, should be a dictionary to use in creating a Context for that template. If you dont provide a second argument, render_to_response() will use an empty dictionary.

render_to_response() 鐨勭涓涓弬鏁板繀椤绘槸瑕佷娇鐢ㄧ殑妯℃澘鍚嶇О銆傚鏋滆缁欏畾绗簩涓弬鏁帮紝閭d箞璇ュ弬鏁板繀椤绘槸涓鸿妯℃澘鍒涘缓 Context 鏃舵墍浣跨敤鐨勫瓧鍏搞傚鏋滀笉鎻愪緵绗簩涓弬鏁帮紝 render_to_response() 浣跨敤涓涓┖瀛楀吀銆

The locals() Trick

locals() 鎶宸

Consider our latest incarnation of current_datetime :

鎬濊冧竴涓嬫垜浠 current_datetime 鐨勬渶鍚庝竴娆¤祴鍊:

def current_datetime(request):
    now = datetime.datetime.now()
    return render_to_response('current_datetime.html', {'current_date': now})

Many times, as in this example, youll find yourself calculating some values, storing them in variables (e.g., now in the preceding code), and sending those variables to the template. Particularly lazy programmers should note that its slightly redundant to have to give names for temporary variables and give names for the template variables. Not only is it redundant, but also its extra typing.

寰堝鏃跺欙紝灏卞儚鍦ㄨ繖涓寖渚嬩腑閭f牱锛屼綘鍙戠幇鑷繁涓鐩村湪璁$畻鏌愪釜鍙橀噺锛屼繚瀛樼粨鏋滃埌鍙橀噺涓紙姣斿锛氬墠闈唬鐮佷腑鐨 now 锛夛紝鐒跺悗灏嗚繖浜涘彉閲忓彂閫佺粰妯℃澘銆傜壒鍒噿鐨勭▼搴忓憳鍙兘娉ㄦ剰鍒扮粰杩欎簺涓存椂鍙橀噺 妯℃澘鍙橀噺鍛藉悕鏄惧緱鏈夌偣澶氫綑銆備笉浣嗗浣欙紝鑰屼笖杩樿杩涜棰濆鐨勯敭鐩樿緭鍏ャ

So if youre one of those lazy programmers and you like keeping code particularly concise, you can take advantage of a built-in Python function called locals() . It returns a dictionary mapping all local variable names to their values. Thus, the preceding view could be rewritten like so:

濡傛灉浣犳槸涓枩娆㈠伔鎳掔殑绋嬪簭鍛樺苟鎯宠浠g爜鐪嬭捣鏉ユ洿鍔犵畝鏄庯紝鍙互鍒╃敤 Python 鐨勫唴寤哄嚱鏁 locals() 銆傚畠杩斿洖鐨勫瓧鍏稿鎵鏈夊眬閮ㄥ彉閲忕殑鍚嶇О涓庡艰繘琛屾槧灏勩傚洜姝わ紝鍓嶉潰鐨勮鍥惧彲浠ラ噸鍐欐垚涓嬮潰杩欎釜鏍峰瓙锛

def current_datetime(request):
    current_date = datetime.datetime.now()
    return render_to_response('current_datetime.html', locals())

Here, instead of manually specifying the context dictionary as before, we pass the value of locals() , which will include all variables defined at that point in the functions execution. As a consequence, weve renamed the now variable to current_date , because thats the variable name that the template expects. In this example, locals() doesnt offer a huge improvement, but this technique can save you some typing if you have several template variables to defineor if youre lazy.

鍦ㄦ锛屾垜浠病鏈夊儚涔嬪墠閭f牱鎵嬪伐鎸囧畾 context 瀛楀吀锛岃屾槸浼犲叆浜 locals() 鐨勫硷紝瀹冨泭鎷簡鍑芥暟鎵ц鍒拌鏃堕棿鐐规椂鎵瀹氫箟鐨勪竴鍒囧彉閲忋傚洜姝わ紝鎴戜滑灏 now 鍙橀噺閲嶅懡鍚嶄负 current_date 锛屽洜涓洪偅鎵嶆槸妯℃澘鎵棰勬湡鐨勫彉閲忓悕绉般傚湪鏈緥涓紝 locals() 骞舵病鏈夊甫鏉ュ 鐨勬敼杩涳紝浣嗘槸濡傛灉鏈夊涓ā鏉垮彉閲忚鐣屽畾鑰屼綘鍙堟兂鍋锋噿锛岃繖绉嶆妧鏈彲浠ュ噺灏戜竴浜涢敭鐩樿緭鍏ャ

One thing to watch out for when using locals() is that it includes every local variable, which may comprise more variables than you actually want your template to have access to. In the previous example, locals() will also include request . Whether this matters to you depends on your application.

浣跨敤 locals() 鏃惰娉ㄦ剰鏄畠灏嗗寘鎷 鎵鏈 鐨勫眬閮ㄥ彉閲忥紝缁勬垚瀹冪殑鍙橀噺鍙兘姣斾綘鎯宠妯℃澘璁块棶鐨勮澶氥傚湪鍓嶄緥涓紝 locals() 杩樺寘鍚簡 request 銆傚姝ゅ浣曞彇鑸嶅彇鍐充綘鐨勫簲鐢ㄧ▼搴忋

A final thing to consider is that locals() incurs a small bit of overhead, because when you call it, Python has to create the dictionary dynamically. If you specify the context dictionary manually, you avoid this overhead.

鏈鍚庤鑰冭檻鐨勬槸鍦ㄤ綘璋冪敤 locals() 鏃讹紝Python 蹇呴』寰楀姩鎬佸垱寤哄瓧鍏革紝鍥犳瀹冧細甯︽潵涓鐐归澶栫殑寮閿銆傚鏋滄墜鍔ㄦ寚瀹 context 瀛楀吀锛屽垯鍙互閬垮厤杩欑寮閿銆

Subdirectories in get_template()

get_template()涓娇鐢ㄥ瓙鐩綍

It can get unwieldy to store all of your templates in a single directory. You might like to store templates in subdirectories of your template directory, and thats fine. In fact, we recommend doing so; some more advanced Django features (such as the generic views system, which we cover in Chapter 9) expect this template layout as a default convention.

鎶婃墍鏈夌殑妯℃澘閮藉瓨鏀惧湪涓涓洰褰曚笅鍙兘浼氳浜嬫儏鍙樺緱闅句互鎺屾帶銆備綘鍙兘浼氳冭檻鎶婃ā鏉垮瓨鏀惧湪浣犳ā鏉跨洰褰曠殑瀛愮洰褰曚腑锛岃繖闈炲父濂姐備簨瀹炰笂锛屾垜浠帹鑽愯繖鏍峰仛锛涗竴浜汥jango鐨勯珮绾х壒鎬э紙渚嬪灏嗗湪绗節绔犺鍒扮殑閫氱敤瑙嗗浘绯荤粺锛夌殑缂虹渷绾﹀畾灏辨槸鏈熸湜浣跨敤杩欑妯℃澘甯冨眬銆

Storing templates in subdirectories of your template directory is easy. In your calls to get_template() , just include the subdirectory name and a slash before the template name, like so:

鎶婃ā鏉垮瓨鏀句簬妯℃澘鐩綍鐨勫瓙鐩綍涓槸浠跺緢杞绘澗鐨勪簨鎯呫傚彧闇鍦ㄨ皟鐢 get_template() 鏃讹紝鎶婂瓙鐩綍鍚嶅拰涓鏉℃枩鏉犳坊鍔犲埌妯℃澘鍚嶇О涔嬪墠锛屽锛

t = get_template('dateapp/current_datetime.html')

Because render_to_response() is a small wrapper around get_template() , you can do the same thing with the first argument to render_to_response() .

鐢变簬 render_to_response() 鍙槸瀵 get_template() 鐨勭畝鍗曞皝瑁咃紝 浣犲彲浠ュ render_to_response() 鐨勭涓涓弬鏁板仛鐩稿悓澶勭悊銆

Theres no limit to the depth of your subdirectory tree. Feel free to use as many as you like.

瀵瑰瓙鐩綍鏍戠殑娣卞害娌℃湁闄愬埗锛屼綘鎯宠澶氬皯灞傞兘鍙互銆

Note

娉ㄦ剰

Windows users, be sure to use forward slashes rather than backslashes. get_template() assumes a Unix-style file name designation.

Windows鐢ㄦ埛蹇呴』浣跨敤鏂滄潬鑰屼笉鏄弽鏂滄潬銆 get_template() 鍋囧畾鐨勬槸 Unix 椋庢牸鐨勬枃浠跺悕绗﹀彿绾﹀畾銆

The include Template Tag

include 妯℃澘鏍囩

Now that weve covered the template-loading mechanism, we can introduce a built-in template tag that takes advantage of it: {% include %} . This tag allows you to include the contents of another template. The argument to the tag should be the name of the template to include, and the template name can be either a variable or a hard-coded (quoted) string, in either single or double quotes. Anytime you have the same code in multiple templates, consider using an {% include %} to remove the duplication.

鍦ㄨ瑙d簡妯℃澘鍔犺浇鏈哄埗涔嬪悗锛屾垜浠啀浠嬬粛涓涓埄鐢ㄨ鏈哄埗鐨勫唴寤烘ā鏉挎爣绛撅細 {% include %} 銆傝鏍囩鍏佽鍦紙妯℃澘涓級鍖呭惈鍏跺畠鐨勬ā鏉跨殑鍐呭銆傛爣绛剧殑鍙傛暟鏄墍瑕佸寘鍚殑妯℃澘鍚嶇О锛屽彲浠ユ槸涓涓彉閲忥紝涔熷彲浠ユ槸鐢ㄥ崟/鍙屽紩鍙风‖缂栫爜鐨勫瓧绗︿覆銆傛瘡褰撳湪澶氫釜妯℃澘涓嚭鐜扮浉鍚岀殑浠g爜鏃讹紝灏卞簲璇ヨ冭檻鏄惁瑕佷娇鐢 {% include %} 鏉ュ噺灏戦噸澶嶃

These two examples include the contents of the template nav.html . The examples are equivalent and illustrate that either single or double quotes are allowed:

涓嬮潰杩欎袱涓緥瀛愰兘鍖呭惈浜 nav.html 妯℃澘銆備袱涓緥瀛愮殑浣滅敤瀹屽叏鐩稿悓锛屽彧涓嶈繃鏄负浜嗚鏄庡崟銆佸弻寮曞彿閮藉彲浠ラ氱敤銆

{% include 'nav.html' %}
{% include "nav.html" %}

This example includes the contents of the template includes/nav.html :

涓嬮潰鐨勪緥瀛愬寘鍚簡 includes/nav.html 妯℃澘鐨勫唴瀹:

{% include 'includes/nav.html' %}

This example includes the contents of the template whose name is contained in the variable template_name :

涓嬮潰鐨勪緥瀛愬寘鍚簡浠ュ彉閲 template_name 鐨勫间负鍚嶇О鐨勬ā鏉垮唴瀹癸細

{% include template_name %}

As in get_template() , the file name of the template is determined by adding the template directory from TEMPLATE_DIRS to the requested template name.

鍜屽湪 get_template() 涓竴鏍凤紝 瀵规ā鏉跨殑鏂囦欢鍚嶈繘琛屽垽鏂椂浼氬湪鎵璋冨彇鐨勬ā鏉垮悕绉颁箣鍓嶅姞涓婃潵鑷 TEMPLATE_DIRS 鐨勬ā鏉跨洰褰曘

Included templates are evaluated with the context of the template thats including them.

鎵鍖呭惈鐨勬ā鏉挎墽琛屾椂鐨 context 鍜屽寘鍚畠浠殑妯℃澘鏄竴鏍风殑銆

If a template with the given name isnt found, Django will do one of two things:

濡傛灉鏈壘鍒扮粰瀹氬悕绉扮殑妯℃澘鏂囦欢锛孌jango 浼氫粠浠ヤ笅涓や欢浜嬫儏涓嫨涓鑰屼负涔嬶細

  • If DEBUG is set to True , youll see the TemplateDoesNotExist exception on a Django error page.

  • 濡傛灉 DEBUG 璁剧疆涓 True 锛屼綘灏嗕細鍦 Django 閿欒淇℃伅椤甸潰鐪嬪埌 TemplateDoesNotExist 寮傚父銆

  • If DEBUG is set to False , the tag will fail silently, displaying nothing in the place of the tag.

  • 濡傛灉 DEBUG 璁剧疆涓 False 锛岃鏍囩涓嶄細寮曞彂閿欒淇℃伅锛屽湪鏍囩浣嶇疆涓嶆樉绀轰换浣曚笢瑗裤

Template Inheritance

妯℃澘缁ф壙

Our template examples so far have been tiny HTML snippets, but in the real world, youll be using Djangos template system to create entire HTML pages. This leads to a common Web development problem: across a Web site, how does one reduce the duplication and redundancy of common page areas, such as sitewide navigation?

鍒扮洰鍓嶄负姝紝鎴戜滑鐨勬ā鏉胯寖渚嬮兘鍙槸浜涢浂鏄熺殑 HTML 鐗囨锛屼絾鍦ㄥ疄闄呭簲鐢ㄤ腑锛屼綘灏嗙敤 Django 妯℃澘绯荤粺鏉ュ垱寤烘暣涓 HTML 椤甸潰銆傝繖灏卞甫鏉ヤ竴涓父瑙佺殑 Web 寮鍙戦棶棰橈細鍦ㄦ暣涓綉绔欎腑锛屽浣曞噺灏戝叡鐢ㄩ〉闈㈠尯鍩燂紙姣斿绔欑偣瀵艰埅锛夋墍寮曡捣鐨勯噸澶嶅拰鍐椾綑浠g爜锛

A classic way of solving this problem is to use server-side includes , directives you can embed within your HTML pages to include one Web page inside another. Indeed, Django supports that approach, with the {% include %} template tag just described. But the preferred way of solving this problem with Django is to use a more elegant strategy called template inheritance .

瑙e喅璇ラ棶棰樼殑浼犵粺鍋氭硶鏄娇鐢 鏈嶅姟鍣ㄧ鐨 includes 锛屼綘鍙互鍦 HTML 椤甸潰涓娇鐢ㄨ鎸囦护灏嗕竴涓綉椤靛祵鍏ュ埌鍙︿竴涓腑銆備簨瀹炰笂锛 Django 閫氳繃鍒氭墠璁茶堪鐨 {% include %} 鏀寔浜嗚繖绉嶆柟娉曘備絾鏄敤 Django 瑙e喅姝ょ被闂鐨勯閫夋柟娉曟槸浣跨敤鏇村姞绠娲佺殑绛栫暐鈥斺 妯℃澘缁ф壙

In essence, template inheritance lets you build a base skeleton template that contains all the common parts of your site and defines blocks that child templates can override.

鏈川涓婃潵璇达紝妯℃澘缁ф壙灏辨槸鍏堟瀯閫犱竴涓熀纭妗嗘灦妯℃澘锛岃屽悗鍦ㄥ叾瀛愭ā鏉夸腑瀵瑰畠鎵鍖呭惈绔欑偣鍏敤閮ㄥ垎鍜屽畾涔夊潡杩涜閲嶈浇銆

Lets see an example of this by creating a more complete template for our current_datetime view, by editing the current_datetime.html file:

璁╂垜浠氳繃淇敼 current_datetime.html 鏂囦欢锛屼负 current_datetime 鍒涘缓涓涓洿鍔犲畬鏁寸殑妯℃澘鏉ヤ綋浼氫竴涓嬭繖绉嶅仛娉曪細

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title>The current time</title>
</head>
<body>
    <h1>My helpful timestamp site</h1>
    <p>It is now {{ current_date }}.</p>

    <hr>
    <p>Thanks for visiting my site.</p>
</body>
</html>

That looks just fine, but what happens when we want to create a template for another viewsay, the hours_ahead view from Chapter 3? If we want again to make a nice, valid, full HTML template, wed create something like:

杩欑湅璧锋潵寰堟锛屼絾濡傛灉鎴戜滑瑕佷负绗笁绔犵殑 hours_ahead 瑙嗗浘鍒涘缓鍙︿竴涓ā鏉夸細鍙戠敓浠涔堜簨鎯呭憿锛熷鏋滄垜浠啀娆″垱寤轰竴涓紓浜佹湁鏁堜笖瀹屾暣鐨 HTML 妯℃澘锛屾垜浠彲鑳戒細鍒涘缓鍑轰笅闈㈣繖鏍风殑涓滆タ锛

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title>Future time</title>
</head>
<body>
    <h1>My helpful timestamp site</h1>
    <p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>

    <hr>
    <p>Thanks for visiting my site.</p>
</body>
</html>

Clearly, weve just duplicated a lot of HTML. Imagine if we had a more typical site, including a navigation bar, a few style sheets, perhaps some JavaScriptwed end up putting all sorts of redundant HTML into each template.

寰堟槑鏄撅紝鎴戜滑鍒氭墠閲嶅浜嗗ぇ閲忕殑 HTML 浠g爜銆傛兂璞′竴涓嬶紝濡傛灉鏈変竴涓洿鍏稿瀷鐨勭綉绔欙紝瀹冩湁瀵艰埅鏉°佹牱寮忚〃锛屽彲鑳借繕鏈変竴浜 JavaScript 浠g爜锛屼簨鎯呭繀灏嗕互鍚戞瘡涓ā鏉垮~鍏呭悇绉嶅啑浣欑殑 HTML 鑰屽憡缁堛

The server-side include solution to this problem is to factor out the common bits in both templates and save them in separate template snippets, which are then included in each template. Perhaps youd store the top bit of the template in a file called header.html :

瑙e喅杩欎釜闂鐨勬湇鍔″櫒绔 include 鏂规鏄壘鍑轰袱涓ā鏉夸腑鐨勫叡鍚岄儴鍒嗭紝灏嗗叾淇濆瓨涓轰笉鍚岀殑妯℃澘鐗囨锛岀劧鍚庡湪姣忎釜妯℃澘涓繘琛 include銆備篃璁镐綘浼氭妸妯℃澘澶撮儴鐨勪竴浜涗唬鐮佷繚瀛樹负 header.html 鏂囦欢锛

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>

And perhaps youd store the bottom bit in a file called footer.html :

浣犲彲鑳戒細鎶婂簳閮ㄤ繚瀛樺埌鏂囦欢 footer.html :

    <hr>
    <p>Thanks for visiting my site.</p>
</body>
</html>

With an include-based strategy, headers and footers are easy. Its the middle ground thats messy. In this example, both pages feature a title <h1>My helpful timestamp site</h1> but that title cant fit into header.html because the <title> on both pages is different. If we included the <h1> in the header, wed have to include the <title> , which wouldnt allow us to customize it per page. See where this is going?

瀵瑰熀浜 include 鐨勭瓥鐣ワ紝澶撮儴鍜屽簳閮ㄧ殑鍖呭惈寰堢畝鍗曘傞夯鐑︾殑鏄腑闂撮儴鍒嗐傚湪姝よ寖渚嬩腑锛屾瘡涓〉闈㈤兘鏈変竴涓 <h1>My helpful timestamp site</h1> 鏍囬锛屼絾鏄繖涓爣棰樹笉鑳芥斁鍦 header.html 涓紝鍥犱负姣忎釜椤甸潰鐨 <title> 鏄笉鍚岀殑銆傚鏋滄垜浠皢 <h1> 鍖呭惈鍦ㄥご閮紝鎴戜滑灏变笉寰椾笉鍖呭惈 <title> 锛屼絾杩欐牱鍙堜笉鍏佽鍦ㄦ瘡涓〉闈㈠瀹冭繘琛屽畾鍒躲備綍鍘讳綍浠庡憿锛

Djangos template inheritance system solves these problems. You can think of it as an inside-out version of server-side includes. Instead of defining the snippets that are common , you define the snippets that are different .

Django 鐨勬ā鏉跨户鎵跨郴缁熻В鍐充簡杩欎簺闂銆備綘鍙互灏嗗叾瑙嗕负鏈嶅姟鍣ㄧ include 鐨勯嗗悜鎬濈淮鐗堟湰銆備綘鍙互瀵归偅浜 涓嶅悓 鐨勪唬鐮佹杩涜瀹氫箟锛岃屼笉鏄 鍏卞悓 浠g爜娈点

The first step is to define a base template a skeleton of your page that child templates will later fill in. Heres a base template for our ongoing example:

绗竴姝ユ槸瀹氫箟 鍩虹妯℃澘 锛 璇ユ鏋朵箣鍚庡皢鐢 瀛愭ā鏉 鎵缁ф壙銆備互涓嬫槸鎴戜滑鐩墠鎵璁茶堪鑼冧緥鐨勫熀纭妯℃澘锛

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    <h1>My helpful timestamp site</h1>
    {% block content %}{% endblock %}
    {% block footer %}
    <hr>
    <p>Thanks for visiting my site.</p>
    {% endblock %}
</body>
</html>

This template, which well call base.html , defines a simple HTML skeleton document that well use for all the pages on the site. Its the job of child templates to override, or add to, or leave alone the contents of the blocks. (If youre following along at home, save this file to your template directory.)

杩欎釜鍙仛 base.html 鐨勬ā鏉垮畾涔変簡涓涓畝鍗曠殑 HTML 妗嗘灦鏂囨。锛屾垜浠皢鍦ㄦ湰绔欑偣鐨勬墍鏈夐〉闈腑浣跨敤銆傚瓙妯℃澘鐨勪綔鐢ㄥ氨鏄噸杞姐佹坊鍔犳垨淇濈暀閭d簺鍧楃殑鍐呭銆傦紙濡傛灉涓鐩存寜鎴戜滑鐨勮寖渚嬪仛璇濓紝璇峰皢姝ゆ枃浠朵繚瀛樺埌妯℃澘鐩綍銆傦級

Were using a template tag here that you havent seen before: the {% block %} tag. All the {% block %} tags do is tell the template engine that a child template may override those portions of the template.

鎴戜滑浣跨敤涓涓互鍓嶆病鏈夎杩囩殑妯℃澘鏍囩锛 {% block %} 銆 鎵鏈夌殑 {% block %} 鏍囩鍛婅瘔妯℃澘寮曟搸锛屽瓙妯℃澘鍙互閲嶈浇杩欎簺閮ㄥ垎銆

Now that we have this base template, we can modify our existing current_datetime.html template to use it:

鐜板湪鎴戜滑宸茬粡鏈変簡涓涓熀鏈ā鏉匡紝鎴戜滑鍙互淇敼 current_datetime.html 妯℃澘鏉 浣跨敤瀹冿細

{% extends "base.html" %}

{% block title %}The current time{% endblock %}

{% block content %}
<p>It is now {{ current_date }}.</p>
{% endblock %}

While were at it, lets create a template for the hours_ahead view from Chapter 3. (If youre following along with code, well leave it up to you to change hours_ahead to use the template system.) Heres what that would look like:

鍐嶄负 hours_ahead 瑙嗗浘鍒涘缓涓涓ā鏉匡紝鐪嬭捣鏉ユ槸杩欐牱鐨勶細

{% extends "base.html" %}

{% block title %}Future time{% endblock %}

{% block content %}
<p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>
{% endblock %}

Isnt this beautiful? Each template contains only the code thats unique to that template. No redundancy needed. If you need to make a site-wide design change, just make the change to base.html , and all of the other templates will immediately reflect the change.

鐪嬭捣鏉ュ緢婕備寒鏄笉鏄紵姣忎釜妯℃澘鍙寘鍚鑷繁鑰岃█ 鐙竴鏃犱簩 鐨勪唬鐮併傛棤闇澶氫綑鐨勯儴鍒嗐傚鏋滄兂杩涜绔欑偣绾х殑璁捐淇敼锛屼粎闇淇敼 base.html 锛屾墍鏈夊叾瀹冩ā鏉夸細绔嬪嵆鍙嶆槧鍑烘墍浣滀慨鏀广

Heres how it works. When you load the template current_datetime.html , the template engine sees the {% extends %} tag, noting that this template is a child template. The engine immediately loads the parent templatein this case, base.html .

浠ヤ笅鏄叾宸ヤ綔鏂瑰紡銆傚湪鍔犺浇 current_datetime.html 妯℃澘鏃讹紝妯℃澘寮曟搸鍙戠幇浜 {% extends %} 鏍囩锛 娉ㄦ剰鍒拌妯℃澘鏄竴涓瓙妯℃澘銆傛ā鏉垮紩鎿庣珛鍗宠杞藉叾鐖舵ā鏉匡紝鍗虫湰渚嬩腑鐨 base.html

At that point, the template engine notices the three {% block %} tags in base.html and replaces those blocks with the contents of the child template. So, the title weve defined in {% block title %} will be used, as will the {% block content %} .

姝ゆ椂锛屾ā鏉垮紩鎿庢敞鎰忓埌 base.html 涓殑涓変釜 {% block %} 鏍囩锛屽苟鐢ㄥ瓙妯℃澘鐨勫唴瀹规浛鎹㈣繖浜 block 銆傚洜姝わ紝寮曟搸灏嗕細浣跨敤鎴戜滑鍦 { block title %} 涓畾涔夌殑鏍囬锛屽 {% block content %} 涔熸槸濡傛銆

Note that since the child template doesnt define the footer block, the template system uses the value from the parent template instead. Content within a {% block %} tag in a parent template is always used as a fallback.

娉ㄦ剰鐢变簬瀛愭ā鏉垮苟娌℃湁瀹氫箟 footer 鍧楋紝妯℃澘绯荤粺灏嗕娇鐢ㄥ湪鐖舵ā鏉夸腑瀹氫箟鐨勫笺傜埗妯℃澘 {% block %} 鏍囩涓殑鍐呭鎬绘槸琚綋浣滀竴鏉¢璺

Inheritance doesnt affect the way the context works, and you can use as many levels of inheritance as needed. One common way of using inheritance is the following three-level approach:

缁ф壙骞朵笉鏀瑰彉 context 鐨勫伐浣滄柟寮忥紝鑰屼笖浣犲彲浠ユ寜鐓ч渶瑕佷娇鐢ㄥ灞傜户鎵裤備娇鐢ㄧ户鎵跨殑涓绉嶅父瑙佹柟寮忔槸涓嬮潰鐨勪笁灞傛硶锛

  1. Create a base.html template that holds the main look and feel of your site. This is the stuff that rarely, if ever, changes.

  1. 鍒涘缓 base.html 妯℃澘锛屽湪鍏朵腑瀹氫箟绔欑偣鐨勪富瑕佸瑙傛劅鍙椼傝繖浜涢兘鏄笉甯镐慨鏀圭敋鑷充粠涓嶄慨鏀圭殑閮ㄥ垎銆

  1. Create a base_SECTION.html template for each section of your site (e.g., base_photos.html and base_forum.html ). These templates extend base.html and include section-specific styles/design.

  1. 涓虹綉绔欑殑姣忎釜鍖哄煙鍒涘缓 base_SECTION.html 妯℃澘(渚嬪, base_photos.htmlbase_forum.html )銆傝繖浜涙ā鏉垮 base.html 杩涜鎷撳睍锛屽苟鍖呭惈鍖哄煙鐗瑰畾鐨勯鏍间笌璁捐銆

  1. Create individual templates for each type of page, such as a forum page or a photo gallery. These templates extend the appropriate section template.

  1. 涓烘瘡绉嶇被鍨嬬殑椤甸潰鍒涘缓鐙珛鐨勬ā鏉匡紝渚嬪璁哄潧椤甸潰鎴栬呭浘鐗囧簱銆傝繖浜涙ā鏉挎嫇灞曠浉搴旂殑鍖哄煙妯℃澘銆

This approach maximizes code reuse and makes it easy to add items to shared areas, such as section-wide navigation.

杩欎釜鏂规硶鍙渶澶ч檺搴﹀湴閲嶇敤浠g爜锛屽苟浣垮緱鍚戝叕鍏卞尯鍩燂紙濡傚尯鍩熺骇鐨勫鑸級娣诲姞鍐呭鎴愪负涓浠惰交鏉剧殑宸ヤ綔銆

Here are some tips for working with template inheritance:

浠ヤ笅鏄娇鐢ㄦā鏉跨户鎵跨殑涓浜涜瘈绐嶏細

  • If you use {% extends %} in a template, it must be the first template tag in that template. Otherwise, template inheritance wont work.

  • 濡傛灉鍦ㄦā鏉夸腑浣跨敤 {% extends %} 锛屽繀椤讳繚璇佸叾涓烘ā鏉夸腑鐨勭涓涓ā鏉挎爣璁般傚惁鍒欙紝妯℃澘缁ф壙灏嗕笉璧蜂綔鐢ㄣ

  • Generally, the more {% block %} tags in your base templates, the better. Remember, child templates dont have to define all parent blocks, so you can fill in reasonable defaults in a number of blocks, and then define only the ones you need in the child templates. Its better to have more hooks than fewer hooks.

  • 涓鑸潵璇达紝鍩虹妯℃澘涓殑 {% block %} 鏍囩瓒婂瓒婂ソ銆傝浣忥紝瀛愭ā鏉夸笉蹇呭畾涔夌埗妯℃澘涓墍鏈夌殑浠g爜鍧楋紝鍥犳浣犲彲浠ョ敤鍚堢悊鐨勭己鐪佸煎涓浜涗唬鐮佸潡杩涜濉厖锛岀劧鍚庡彧瀵瑰瓙妯℃澘鎵闇鐨勪唬鐮佸潡杩涜锛堥噸锛夊畾涔夈備織璇濊锛岄挬瀛愯秺澶氳秺濂姐

  • If you find yourself duplicating code in a number of templates, it probably means you should move that code to a {% block %} in a parent template.

  • 濡傛灉鍙戣鑷繁鍦ㄥ涓ā鏉夸箣闂存嫹璐濅唬鐮侊紝浣犲簲璇ヨ冭檻灏嗚浠g爜娈垫斁缃埌鐖舵ā鏉跨殑鏌愪釜 {% 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.

  • 濡傛灉闇瑕佽幏寰楃埗妯℃澘涓唬鐮佸潡鐨勫唴瀹癸紝鍙互浣跨敤 {{ block.super }} 鍙橀噺銆傚鏋滃彧鎯冲湪涓婄骇浠g爜鍧楀熀纭涓婃坊鍔犲唴瀹癸紝鑰屼笉鏄叏閮ㄩ噸杞斤紝璇ュ彉閲忓氨鏄惧緱闈炲父鏈夌敤浜嗐

  • You may not define multiple {% block %} tags with the same name in the same template. This limitation exists because a block tag works in both directions. That is, a block tag doesnt just provide a hole to fill, it also defines the content that fills the hole in the parent . If there were two similarly named {% block %} tags in a template, that templates parent wouldnt know which one of the blocks content to use.

  • 涓嶅彲鍚屼竴涓ā鏉夸腑瀹氫箟澶氫釜鍚屽悕鐨 {% block %} 銆傚瓨鍦ㄨ繖鏍风殑闄愬埗鏄洜涓篵lock 鏍囩鐨勫伐浣滄柟寮忔槸鍙屽悜鐨勩備篃灏辨槸璇达紝block 鏍囩涓嶄粎鎸栦簡涓涓濉殑鍧戯紝涔熷畾涔変簡鍦 妯℃澘涓繖涓潙鎵濉厖鐨勫唴瀹广傚鏋滄ā鏉夸腑鍑虹幇浜嗕袱涓浉鍚屽悕绉扮殑 {% block %} 鏍囩锛岀埗妯℃澘灏嗘棤浠庡緱鐭ヨ浣跨敤鍝釜鍧楃殑鍐呭銆

  • The template name you pass to {% extends %} is loaded using the same method that get_template() uses. That is, the template name is appended to your TEMPLATE_DIRS setting.

  • {% extends %} 瀵规墍浼犲叆妯℃澘鍚嶇О浣跨敤鐨勫姞杞芥柟娉曞拰 get_template() 鐩稿悓銆備篃灏辨槸璇达紝浼氬皢妯℃澘鍚嶇О琚坊鍔犲埌 TEMPLATE_DIRS 璁剧疆涔嬪悗銆

  • In most cases, the argument to {% extends %} will be a string, but it can also be a variable, if you dont know the name of the parent template until runtime. This lets you do some cool, dynamic stuff.

  • 澶氭暟鎯呭喌涓嬶紝 {% extends %} 鐨勫弬鏁板簲璇ユ槸瀛楃涓诧紝浣嗘槸濡傛灉鐩村埌杩愯鏃舵柟鑳界‘瀹氱埗妯℃澘鍚嶏紝杩欎釜鍙傛暟涔熷彲浠ユ槸涓彉閲忋傝繖浣垮緱浣犺兘澶熷疄鐜颁竴浜涘緢閰风殑鍔ㄦ佸姛鑳姐

Whats next?

鎺ヤ笅鏉ワ紵

Most modern Web sites are database-driven : the content of the Web site is stored in a relational database. This allows a clean separate of data and logic (in the same way views and templates allow the separation of logic and display.)

鏃朵笅澶у鏁扮綉绔欓兘鏄 鏁版嵁搴撻┍鍔 鐨勶細缃戠珯鐨勫唴瀹归兘鏄瓨鍌ㄥ湪鍏崇郴鍨嬫暟鎹簱涓傝繖浣垮緱鏁版嵁鍜岄昏緫鑳藉褰诲簳鍦板垎寮锛堣鍥惧拰妯℃澘涔熶互鍚屾牱鏂瑰紡瀵归昏緫鍜屾樉绀鸿繘琛屼簡鍒嗛殧銆傦級

The next chapter covers the tools Django gives you to interact with a database.

鍦ㄤ笅涓绔犻噷灏嗚杩 Django 鎻愪緵鐨勬暟鎹簱浜や簰宸ュ叿銆

Copyright 2006 Adrian Holovaty and Jacob Kaplan-Moss.
This work is licensed under the GNU Free Document License.
Hosting graciously provided by media temple
Chinese translate hosting by py3k.cn.