Django模板繼承和靜態文件
模板繼承(extend)
Django模板引擎中最強大也是最復雜的部分就是模板繼承了,模板繼承可以讓我們創建一個基本的"骨架"模板,它可以包含網頁中的全部元素,並且可以定義能夠被子模板覆蓋的blocks。為了容易理解模板繼承,我們先寫一個模板:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}Replaceable template{% endblock %}</title>
</head>
<body>
<div id="sidebar">
{% block sidebar %}
<ul>
<li><a href="/">Home</a> </li>
<li><a href="/blog">Blog</a> </li>
</ul>
{% endblock %}
</div>
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
</html>
這個模板,我們把它叫做base.html,它定義了一個可以用於兩列排版頁面的簡單HTML骨架。"子模板"可以用它們的內容填充空白的blocks。在這個例子中,block標簽定義了三個可以被子模板內容填充的block,block告訴模板引擎:子模板可能會覆蓋掉模板中的這些位置。
接下來,我們再寫一個子模板:
{% extends "polls/base.html" %} # 模板路徑根據項目或者app的路徑來寫,筆者這里的模板位於app中
{% block title %}Child template{% endblock %}
{% block content %}
{% for entry in blog_entries %}
<h3>{{ entry.title }}</h3>
<p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}
extends標簽是這里的關鍵,它告訴模板引擎這個模板繼承了另一個模板。當模板系統處理這個模板時,首先定位父模板--此例中,就是"base.html"。那時模板引擎注意到base.html中的三個block標簽,並用子模板中的內容來替換這些block。根據blog_entries的值,子模板輸出的內容會是下面的內容:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css" />
<title>Child template</title>
</head>
<body>
<div id="sidebar">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog/">Blog</a></li>
</ul>
</div>
<div id="content">
<h2>Entry one</h2>
<p>This is my first entry.</p>
<h2>Entry two</h2>
<p>This is my second entry.</p>
</div>
</body>
</html>
注意:子模板並沒有定義sidebar block,所以系統使用了父模板中的值。父模板的{% block %}標簽中的內容總是被用作備選內容。這種方式使代碼得到最大程度的復用,並且使得添加內容到共享的內容區域更加簡單,例如:部分范圍內的導航。
說明:
1.如果在模板中使用{% extends %}標簽,它必須是模板中的第一個標簽,其他的任何情況下,模板繼承都將無法工作;
2.在base模版中設置越多的 {% block %} 標簽越好。請記住,子模版不必定義全部父模版中的block,所以,我們可以在大多數>block中填充合理的默認內容,然后,只定義我們需要的那一個。多一點鈎子總比少一點好;
3.如果發現我們在大量的模板中復制內容,那就意味着我們應該把內容移動到父模板中的一個{% block %}中;
4.有時候,想在父模板的基礎上再添加點其他的,而不是完全覆蓋父模板的內容,那么我們只需要在想要填充的塊里,再加上 >{{ block.super }}語句,我們就可以把父模板里的東西給留下來,如:
父模板中的
{% block title %}Parent template{% endblock %}
如果我們只想子模板的結果是在后面添加一個!,則只需要在子模板中寫成
{% block title %}
{{ block.super }}!
{% endblock %}
5.為了更好的可讀性,也可以給我們的 {% endblock %} 標簽一個 名字 。例如:
{% block content %}
...
{% endblock content %}
6.在大型模板中,這個方法可以幫助我們清楚的看到哪個 {% block %}標簽被關閉了;
最后,請注意我們不能在一個模版中定義多個相同名字的 block 標簽。這個限制的存在是因為block標簽的作用是“雙向”的。這個意思是,block標簽不僅提供了一個坑去填,它還在父模版中定義了填坑的內容。如果在一個模版中有兩個名字一樣的 block 標簽,子模版的父模版將不知道使用哪個block的內容。
注意:模板一般放在app下的templates中,Django會自動去這個文件夾中找。但 假如我們每個app的templates中都有一個 index.html,當我們在views.py中使用的時候,直接寫一個 render(request, 'index.html'),Django 能不能找到當前 app 的 templates 文件夾中的 index.html 文件夾呢?(答案是不一定能,有可能找錯)
Django模板查找機制:Django 查找模板的過程是在每個 app 的 templates 文件夾中找(而不只是當前 app 中的代碼,只在當前 app 的 templates 文件夾中找)。各個 app 的 templates 形成一個文件夾列表,Django 遍歷這個列表,一個個文件夾進行查找,當在某一個文件夾找到的時候就停止,所有的都遍歷完了還找不到指定的模板的時候就是 Template Not Found (過程類似於Python找包)。這樣設計有利當然也有弊,有利是的地方是一個app可以用另一個app的模板文件,弊是有可能會找錯了。所以我們使用的時候在 templates 中建立一個 app 同名的文件夾,這樣就好了。這就需要把每個app中的 templates 文件夾中再建一個 app 的名稱,僅和該app相關的模板放在 app/templates/app/ 目錄下面。這樣在使用的時候,有app作為名稱的一部分,就不會混淆。
模板include
假如我們有以下模板index.html,代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>網頁公共頭部部分</div>
<h2> 網頁body部分 </h2>
<div>網頁公共底部部分</div>
</body>
</html>
做過web開發的同學都知道大部分網頁的公共頭部,公共底部部分代碼每個頁面都一樣,那么就應該將其單獨拿出做為一個html, 這樣修改這部分代碼時候,不需要每個頁面都修改, 所以在django中我們可以這么做:
top.html
<div>網頁公共頭部部分</div>
bottom.html
<div>網頁公共底部部分</div>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% include 'top.html' %}
<h2> 網頁body部分 </h2>
{% include 'bottom.html' %}
</body>
</html>
我們可以使用Django模板引擎的include語法,來將單獨的頁面包含到當前模板頁面中。有同學有疑問,那我們通過視圖傳遞給模板的上下文,在被包含的模板中可以使用嗎?可以直接使用,假如我們的視圖函數如下:
def index(request):
return render(request, 'polls/index.html', {'a': 100, 'b': 200})
該Django視圖函數,傳遞給模板並渲染模板。
top.html修改如下:
<div>網頁公共頭部部分:{{ a }}</div> # 這樣使用沒有任何問題
我這里有這樣的一個問題,假如所有的頁面都使用共同的頭部top.html, 可能針對1.html 2.html 3.html所使用的頭部有些樣式不一樣,所需top.html:
<div classs='acss'>網頁公共頭部部分</div>
但是對於5.html, 6.html使用的頭部樣式為:
<div class='bcss'>網頁公共頭部部分</div>
很顯然,如果直接通過include方式包含公共頭部,會導致一些頁面顯示問題。既然部分參數不一樣,include允許我們傳遞參數給被include的模板,我們可以使用with語法,那么問題解決如下:
{{ % include 'top.html' with mycss='acss' % }}
top.html修改如下:
<div class='{{mycss}}'>網頁公共頭部部分</div>
被包含模板中部分參數,由我們include的時候動態指定,那么top.html就不會因為細微差別而編寫多份代碼了。
靜態文件配置
我們自己導入的一些頁面相關的包就叫做靜態文件
- 在app目錄中先創建static目錄;
- 在static目錄里面導入我們的JS、CSS、Jquery和Bootstrap等;
- 在項目settings.py中添加一些配置;
STATIC_URL = '/static/' #這個配置就相當於下面配置的別名,如果這里的名字修改了就按照這里的名字去導入
STATICFILES_DIRS = [
os.path.join(BASE_DIR,"static") #E:\day68\static 找到static路徑
]
- 導入網頁相關圖片、CSS、JS、Jquery等
<link rel = "stysheet",href= "/static/index.css/">
<link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">