WEB框架-Django框架學習(一)-基礎層級關係

今日主要內容爲Django架構,主要有路由層,視圖層和模板層php

1. Django的路由層

URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL與要爲該URL調用的視圖函數之間的映射表;你就是以這種方式告訴Django,對於客戶端發來的某個URL調用哪一段邏輯代碼對應執行。css

1.1 普通路由控制

普通路由控制就是咱們就是最經常使用的打開urls文件,告訴Django,客戶端調用某個URL就調用哪一段邏輯代碼來對應執行。html

from django.urls import path,re_path

from app01 import views

urlpatterns = [
path('admin/', admin.site.urls),
path('timer/',views.timer),
path('login.html/',views.login,name= 'Log'),
re_path(r'^articles/2003/$', views.special_case_2003),
re_path(r'^articles/([0-9]{4})/$', views.year_archive),
re_path(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
re_path(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]

這個就是咱們普通路由控制,告訴django去那裏執行什麼代碼。python

注意:這個時候就有無名分組的定義,若是想要從url中捕獲固定的參數,只須要在它周圍放置一對圓括號,而無名分組就至關於位置參數。 不須要添加一個前導的反斜槓,由於每一個URL 都有。例如,應該是^articles 而不是 ^/articles。 每一個正則表達式前面的'r' 是可選的可是建議加上。它告訴Python 這個字符串是「原始的」 —— 字符串中任何字符都不該該轉義 。web

1.2 有名分組

爲了捕獲固定的參數,在參數前加入「?p<參數>」,就至關於關鍵字參數ajax

上面的示例使用簡單的、沒有命名的正則表達式組(經過圓括號)來捕獲URL 中的值並以位置 參數傳遞給視圖。在更高級的用法中,可使用命名的正則表達式組來捕獲URL 中的值並以關鍵字 參數傳遞給視圖。 在Python 正則表達式中,命名正則表達式組的語法是(?Ppattern),其中name 是組的名稱,pattern 是要匹配的模式。 下面是以上URLconf 使用命名組的重寫:正則表達式

from django.urls import path,re_path

from app01 import views

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

不過上面有名分組有一些要注意的點數據庫

  • 視圖函數在調用路由層的變量,須要使用相同的名字,位置變換沒有關係
  • url有幾個分組,視圖函數必需要接收幾個參數

這個實現與前面的示例徹底相同,只有一個細微的差異:捕獲的值做爲關鍵字參數而不是位置參數傳遞給視圖函數。例如:django

/articles/2005/03/ 請求將調用views.month_archive(request, year='2005', month='03')函數,而不是views.month_archive(request, '2005', '03')。
/articles/2003/03/03/ 請求將調用函數views.article_detail(request, year='2003', month='03', day='03')。

1.3 路由分發

在往後APP數量逐漸的增長,單個app的路由沒有辦法繼續服務,這個時候在項目頂層的urls就至關於頂層urls,在判斷前面的url後丟給APP自身的urls判斷路由。減小頂層urls的工做量。瀏覽器

在頂層路由層的設置

from django.contrib import admin
from django.urls import path,re_path,include

urlpatterns = [
    # 頂層urls
    path("app01/",include("app01.urls")),
    path("app02/",include("app02.urls"))
]

在APP內的分路由層

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


urlpatterns = [
    path('time/',views.timer)
]

#APP02
from django.urls import path,re_path,include
from app02 import views


urlpatterns = [
    path('time/',views.timer)
]

在各自APP內處理本身的邏輯,展現頁面

1.4 反向解析

反向解析,對於一個web應用,他的web應用的url不會一成不變,這個時候若是須要更換的話,就須要更改內部關聯的url,那麼爲了更好的管理,這個時候就須要反向解析,反向解析分爲倆種。

1.4.1 模板層的反向解析

下面開始演示模板層的反向解析

(1).在urls中設定路由,同時爲這條路由設定別名

image_thumb1

(2).在模板層html網頁中,設定action路徑,設定爲{% url ‘路由別名’%}

image_thumb3

(3).在網頁中顯示,f12發現action已經更改成/login/了。

image_thumb5

(4).在返回urls中修改路由,可是別名不動

image_thumb9

(5).從新啓動網頁,按f12咱們發現action已經更改成「/login123/」,見證奇蹟,之後再變動網頁url,只須要在路由層變動後,其餘會自動跟着變動。

image_thumb111

其餘類型:

  • 位置傳參(無名分組){% url 'name' arg1 arg2 ... %}
  • 關鍵字傳參(有名分組){% url 'name' key1=val1 key2=val2 ... %}

1.4.2 在python中的反向解析

下面開始演示python中的反向解析

(1)首先引用

from django.urls import reverse
from django.shortcuts import render,redirect
用reverse解析出要跳轉的網頁,而後用redirect來跳轉到指定的網頁

image_thumb13

這樣咱們在前面urls更改後,仍是會跳轉到指定的網頁中!

(2)帶參數的引用

對於參數的引用與在模板層中一致

當命名你的URL 模式時,請確保使用的名稱不會與其它應用中名稱衝突。若是你的URL 模式叫作comment,而另一個應用中也有一個一樣的名稱,當你在模板中使用這個名稱的時候不能保證將插入哪一個URL。在URL 名稱中加上一個前綴,好比應用的名稱,將減小衝突的可能。咱們建議使用myapp-comment 而不是comment。

1.5 命名空間

命名空間(英語:Namespace)是表示標識符的可見範圍。一個標識符可在多個命名空間中定義,它在不一樣命名空間中的含義是互不相干的。這樣,在一個新的命名空間中可定義任何標識符,它們不會與任何已有的標識符發生衝突,由於已有的定義都處於其它命名空間中。 因爲name沒有做用域,Django在反解URL時,會在項目全局順序搜索,當查找到第一個name指定URL時,當即返回 咱們在開發項目時,會常用name屬性反解出URL,當不當心在不一樣的app的urls中定義相同的name時,可能會致使URL反解錯誤,爲了不這種事情發生,引入了命名空間。

2 Django的視圖層

2.1 視圖函數

一個視圖函數,簡稱視圖,是一個簡單的Python 函數,它接受Web請求而且返回Web響應。響應能夠是一張網頁的HTML內容,一個重定向,一個404錯誤,一個XML文檔,或者一張圖片. . . 是任何東西均可以。不管視圖自己包含什麼邏輯,都要返回響應。代碼寫在哪裏也無所謂,只要它在你的Python目錄下面。除此以外沒有更多的要求了——能夠說「沒有什麼神奇的地方」。爲了將代碼放在某處,約定是將視圖放置在項目或應用程序目錄中的名爲views.py的文件中。 下面是一個返回當前日期和時間做爲HTML文檔的視圖:

from django.urls import reverse
from django.shortcuts import render,redirect,HttpResponse

# Create your views here.

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

讓咱們逐行閱讀上面的代碼:

  • 首先,咱們從 django.shortcuts模塊導入了HttpResponse類,以及Python的datetime庫。

  • 接着,咱們定義了current_datetime函數。它就是視圖函數。每一個視圖函數都使用HttpRequest對象做爲第一個參數,而且一般稱之爲request

    注意,視圖函數的名稱並不重要;不須要用一個統一的命名方式來命名,以便讓Django識別它。咱們將其命名爲current_datetime,是由於這個名稱可以精確地反映出它的功能。

     

  • 這個視圖會返回一個HttpResponse對象,其中包含生成的響應。每一個視圖函數都負責返回一個HttpResponse對象。

視圖層,熟練掌握兩個對象便可:請求對象(request)和響應對象(HttpResponse)

2.2 HttpRequest對象

2.2.1 request的屬性

django將請求報文中的請求行、首部信息、內容主體封裝成 HttpRequest 類中的屬性。 除了特殊說明的以外,其餘均爲只讀的。

1.HttpRequest.GET
  一個相似於字典的對象,包含 HTTP GET 的全部參數。詳情請參考 QueryDict 對象。

   request.GET.get("key") # 推薦寫法

   request.GET.getlist("key") # 返回一個多值的列表

   request.GET["key"] # 不推薦,會報錯

 

2.HttpRequest.POST
  一個相似於字典的對象,若是請求中包含表單數據,則將這些數據封裝成 QueryDict 對象。
  POST 請求能夠帶有空的 POST 字典 —— 若是經過 HTTP POST 方法發送一個表單,可是表單中沒有任何的數據,QueryDict 對象依然會被建立。
   所以,不該該使用 if request.POST  來檢查使用的是不是POST 方法;應該使用 if request.method == "POST"
  另外:若是使用 POST 上傳文件的話,文件信息將包含在 FILES 屬性中。
     注意:鍵值對的值是多個的時候,好比checkbox類型的input標籤,select標籤,須要用:
        request.POST.getlist("hobby")

    request.POST.get("key") # 推薦寫法

    request.POST.getlist("key") # 返回一個多值的列表

    request.POST["key"] # 不推薦,會報錯

3.HttpRequest.body
  一個字符串,表明請求報文的主體。在處理非 HTTP 形式的報文時很是有用,例如:二進制圖片、XML,Json等。
  可是,若是要處理表單數據的時候,推薦仍是使用 HttpRequest.POST 。

4.HttpRequest.path
  一個字符串,表示請求的路徑組件(不含域名,沒有ip以及端口)。
  例如:"/music/bands/the_beatles/"

5.HttpRequest.method
  一個字符串,表示請求使用的HTTP 方法。必須使用大寫。
  例如:"GET""POST"

6.HttpRequest.encoding
  一個字符串,表示提交的數據的編碼方式(若是爲 None 則表示使用 DEFAULT_CHARSET 的設置,默認爲 'utf-8')。
   這個屬性是可寫的,你能夠修改它來修改訪問表單數據使用的編碼。
   接下來對屬性的任何訪問(例如從 GET 或 POST 中讀取數據)將使用新的 encoding 值。
   若是你知道表單數據的編碼不是 DEFAULT_CHARSET ,則使用它。

7.HttpRequest.META
   一個標準的Python 字典,包含全部的HTTP 首部。具體的頭部信息取決於客戶端和服務器,下面是一些示例:
    CONTENT_LENGTH —— 請求的正文的長度(是一個字符串)。
    CONTENT_TYPE —— 請求的正文的MIME 類型。
    HTTP_ACCEPT —— 響應可接收的Content-Type。
    HTTP_ACCEPT_ENCODING —— 響應可接收的編碼。
    HTTP_ACCEPT_LANGUAGE —— 響應可接收的語言。
    HTTP_HOST —— 客服端發送的HTTP Host 頭部。
    HTTP_REFERER —— Referring 頁面。
    HTTP_USER_AGENT —— 客戶端的user-agent 字符串。
    QUERY_STRING —— 單個字符串形式的查詢字符串(未解析過的形式)。
    REMOTE_ADDR —— 客戶端的IP 地址。
    REMOTE_HOST —— 客戶端的主機名。
    REMOTE_USER —— 服務器認證後的用戶。
    REQUEST_METHOD —— 一個字符串,例如"GET""POST"。
    SERVER_NAME —— 服務器的主機名。
    SERVER_PORT —— 服務器的端口(是一個字符串)。
   從上面能夠看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 以外,請求中的任何 HTTP 首部轉換爲 META 的鍵時,
    都會將全部字母大寫並將鏈接符替換爲下劃線最後加上 HTTP_  前綴。
    因此,一個叫作 X-Bender 的頭部將轉換成 META 中的 HTTP_X_BENDER 鍵。

8.HttpRequest.FILES
  一個相似於字典的對象,包含全部的上傳文件信息。
   FILES 中的每一個鍵爲<input type="file" name="" /> 中的name,值則爲對應的數據。
  注意,FILES 只有在請求的方法爲POST 且提交的<form> 帶有enctype="multipart/form-data" 的狀況下才會
   包含數據。不然,FILES 將爲一個空的相似於字典的對象。

9.HttpRequest.COOKIES
  一個標準的Python 字典,包含全部的cookie。鍵和值都爲字符串。

10.HttpRequest.session
   一個既可讀又可寫的相似於字典的對象,表示當前的會話。只有當Django 啓用會話的支持時纔可用。
    完整的細節參見會話的文檔。

11.HttpRequest.user(用戶認證組件下使用)
  一個 AUTH_USER_MODEL 類型的對象,表示當前登陸的用戶。
  若是用戶當前沒有登陸,user 將設置爲 django.contrib.auth.models.AnonymousUser 的一個實例。你能夠經過 is_authenticated() 區分它們。

    例如:
    if request.user.is_authenticated():
        # Do something for logged-in users.
    else:
        # Do something for anonymous users.
       user 只有當Django 啓用 AuthenticationMiddleware 中間件時纔可用。
     -------------------------------------------------------------------------------------
    匿名用戶
    class models.AnonymousUser
    django.contrib.auth.models.AnonymousUser 類實現了django.contrib.auth.models.User 接口,但具備下面幾個不一樣點:
    id 永遠爲None。
    username 永遠爲空字符串。
    get_username() 永遠返回空字符串。
    is_staff 和 is_superuser 永遠爲False。
    is_active 永遠爲 False。
    groups 和 user_permissions 永遠爲空。
    is_anonymous() 返回True 而不是False。
    is_authenticated() 返回False 而不是True。
    set_password()、check_password()、save() 和delete() 引起 NotImplementedError。
    New in Django 1.8:
    新增 AnonymousUser.get_username() 以更好地模擬 django.contrib.auth.models.User。

2.2.2 request的方法

request經常使用方法

1.HttpRequest.get_full_path()
  返回 path,若是能夠將加上查詢字符串,主要是和。
  例如:"/music/bands/the_beatles/?print=true"
2.HttpRequest.is_ajax()
  若是請求是經過XMLHttpRequest 發起的,則返回True,方法是檢查 HTTP_X_REQUESTED_WITH 相應的首部是不是字符串'XMLHttpRequest'。
  大部分現代的 JavaScript 庫都會發送這個頭部。若是你編寫本身的 XMLHttpRequest 調用(在瀏覽器端),你必須手工設置這個值來讓 is_ajax() 能夠工做。
  若是一個響應須要根據請求是不是經過AJAX 發起的,而且你正在使用某種形式的緩存例如Django 的 cache middleware,
   你應該使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 裝飾你的視圖以讓響應可以正確地緩存。

2.3 HttpResponse對象

響應對象主要是如下三種方式

  1. HttpResponse("想要顯示的內容")

  2. render(request, "模板名稱", [ 可選參數])

  3. redirect("要跳轉的URL地址")

(1.)HttpResponse()括號內直接跟一個具體的字符串做爲響應體,比較直接很簡單,因此這裏主要介紹後面兩種形式。
(2.) render()的參數

request: 用於生成響應的請求對象。
template_name:要使用的模板的完整名稱,可選的參數
context:添加到模板上下文的一個字典。默認是一個空字典。若是字典中的某個值是可調用的,視圖將在渲染模板以前調用它。
render方法就是將一個模板頁面中的模板語法進行渲染,最終渲染成一個html頁面做爲響應體。

(3.) redirect()重定向其餘網頁

key:兩次請求 

1)301和302的區別。
  301和302狀態碼都表示重定向,就是說瀏覽器在拿到服務器返回的這個狀態碼後會自動跳轉到一個新的URL地址,這個地址能夠從響應的Location首部中獲取
  (用戶看到的效果就是他輸入的地址A瞬間變成了另外一個地址B)——這是它們的共同點。
  他們的不一樣在於。301表示舊地址A的資源已經被永久地移除了(這個資源不可訪問了),搜索引擎在抓取新內容的同時也將舊的網址交換爲重定向以後的網址;
  302表示舊地址A的資源還在(仍然能夠訪問),這個重定向只是臨時地從舊地址A跳轉到地址B,搜索引擎會抓取新的內容而保存舊的網址。 SEO302好於301
2)重定向緣由:
(1)網站調整(如改變網頁目錄結構);
(2)網頁被移到一個新地址;
(3)網頁擴展名改變(如應用須要把.php改爲.Html或.shtml)。
        這種狀況下,若是不作重定向,則用戶收藏夾或搜索引擎數據庫中舊地址只能讓訪問客戶獲得一個404頁面錯誤信息,訪問流量白白喪失;再者某些註冊了多個域名的
    網站,也須要經過重定向讓訪問這些域名的用戶自動跳轉到主站點等。

3. Django的模板層

3.1 模板語法之變量

在 Django 模板中遍歷複雜數據結構的關鍵是句點字符, 語法:

{{ var_name }}

views.py

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

template

<h4>{{s}}</h4>
<h4>列表:{{ l.0 }}</h4>
<h4>列表:{{ l.2 }}</h4>
<h4>字典:{{ dic.name }}</h4>
<h4>日期:{{ date.year }}</h4>
<h4>類對象列表:{{ person_list.0.name }}</h4>

注意:句點符也能夠用來引用對象的方法(無參數方法):

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

3.2 模板語法之過濾器

語法:{{obj|filter__name:param}}

default:若是一個變量是false或者爲空,使用給定的默認值。不然,使用變量的值。例如:

{{ value|default:"nothing" }}

length:

length:返回值的長度。它對字符串和列表都起做用。例如:
{{ value|length }}
若是 value 是 ['a', 'b', 'c', 'd'],那麼輸出是 4。

filesizeformat:

filesizeformat:將值格式化爲一個 「人類可讀的」 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等):
例如:
{{ value|filesizeformat }}
若是 value 是 123456789,輸出將會是 117.7 MB。

data:

date:若是 value=datetime.datetime.now()
{{ value|date:"Y-m-d" }}

truncatechars:

truncatechars:若是字符串字符多於指定的字符數量,那麼會被截斷。截斷的字符串將以可翻譯的省略號序列(「...」)結尾。
參數:要截斷的字符數
例如:{{ value|truncatechars:10 }}

safe:(用的超級多)

Django的模板中會對HTML標籤和JS等語法標籤進行自動轉義,緣由顯而易見,這樣是爲了安全。可是有的時候咱們可能不但願這些HTML元素被轉義,好比咱們作一個內容管理系統,後臺添加的文章中是通過修飾的,這些修飾多是經過一個相似於FCKeditor編輯加註了HTML修飾符的文本,若是自動轉義的話顯示的就是保護HTML標籤的源文件。爲了在Django中關閉HTML的自動轉義有兩種方式,若是是一個單獨的變量咱們能夠經過過濾器「|safe」的方式告訴Django這段代碼是安全的沒必要轉義。好比:
value="<a href="">點擊</a>"
{{ value|safe }}

3.3 模板之標籤

標籤看起來像是這樣的: {% tag %}。標籤比變量更加複雜:一些在輸出中建立文本,一些經過循環或邏輯來控制流程,一些加載其後的變量將使用到的額外信息到模版中。一些標籤須要開始和結束標籤 (例如{% tag %} ...標籤 內容 ... {% endtag %})。

3.3.1 for標籤

做用:遍歷每個元素:

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

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

遍歷一個字典:

{% for key,val in dic.items %}
    <p>{{ key }}:{{ val }}</p>
{% endfor %}

注:循環序號能夠經過{{forloop}}顯示  

forloop.counter            The current iteration of the loop (1-indexed)
forloop.counter0           The current iteration of the loop (0-indexed)
forloop.revcounter         The number of iterations from the end of the loop (1-indexed)
forloop.revcounter0        The number of iterations from the end of the loop (0-indexed)
forloop.first              True if this is the first time through the loop
forloop.last               True if this is the last time through the loop

3.3.2 for…empty

for 標籤帶有一個可選的{% empty %} 從句,以便在給出的組是空的或者沒有被找到時,能夠有所操做。

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

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

3.3.3 if標籤

{% if %}會對一個變量求值,若是它的值是「True」(存在、不爲空、且不是boolean類型的false值),對應的內容塊會輸出。

{% if num > 100 or num < 0 %}
    <p>無效</p>
{% elif num > 80 and num < 100 %}
    <p>優秀</p>
{% else %}
    <p>湊活吧</p>
{% endif %}

3.3.4 with標籤

使用一個簡單地名字緩存一個複雜的變量,當你須要使用一個「昂貴的」方法(好比訪問數據庫)不少次的時候是很是有用的

例如:

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

3.3.5 csrf_token

這個標籤用於跨站請求僞造保護

3.4 自定義標籤與過濾器

一、在settings中的INSTALLED_APPS配置當前app,否則django沒法找到自定義的simple_tag.

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

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

from django import template
from django.utils.safestring import mark_safe
 
register = template.Library()   #register的名字是固定的,不可改變
 
 
@register.filter
def filter_multi(v1,v2):
    return  v1 * v2
<br>
@register.simple_tag
def simple_tag_multi(v1,v2):
    return  v1 * v2
<br>
@register.simple_tag
def my_input(id,arg):
    result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
    return mark_safe(result)

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

{% load my_tags %}

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

-------------------------------.html
{% load xxx %}   
      
# num=12
{{ num|filter_multi:2 }} #24
 
{{ num|filter_multi:"[22,333,4444]" }}
 
{% simple_tag_multi 2 5 %}  參數不限,但不能放在if for語句中
{% simple_tag_multi num 5 %}

注意:filter能夠用在if等語句後,simple_tag不能夠

{% if num|filter_multi:30 > 100 %}
    {{ num|filter_multi:30 }}
{% endif %}

3.5 模板繼承(extend)

Django模版引擎中最強大也是最複雜的部分就是模版繼承了。模版繼承可讓您建立一個基本的「骨架」模版,它包含您站點中的所有元素,而且能夠定義可以被子模版覆蓋的 blocks 。

經過從下面這個例子開始,能夠容易的理解模版繼承:

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

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

    <div id="content">
        {% block content %}{% endblock %}
    </div>
</body>
</html>

這個模版,咱們把它叫做 base.html, 它定義了一個能夠用於兩列排版頁面的簡單HTML骨架。「子模版」的工做是用它們的內容填充空的blocks。

在這個例子中, block 標籤訂義了三個能夠被子模版內容填充的block。 block 告訴模版引擎: 子模版可能會覆蓋掉模版中的這些位置。

子模版可能看起來是這樣的:

{% extends "base.html" %}
 
{% block title %}My amazing blog{% endblock %}
 
{% block content %}
{% for entry in blog_entries %}
    <h2>{{ entry.title }}</h2>
    <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>My amazing blog</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 %} 標籤中的內容老是被用做備選內容(fallback)。

這種方式使代碼獲得最大程度的複用,而且使得添加內容到共享的內容區域更加簡單,例如,部分範圍內的導航。

這裏是使用繼承的一些提示:

  • 若是你在模版中使用 {% extends %} 標籤,它必須是模版中的第一個標籤。其餘的任何狀況下,模版繼承都將沒法工做。

  • 在base模版中設置越多的 {% block %} 標籤越好。請記住,子模版沒必要定義所有父模版中的blocks,因此,你能夠在大多數blocks中填充合理的默認內容,而後,只定義你須要的那一個。多一點鉤子總比少一點好。

  • 若是你發現你本身在大量的模版中複製內容,那可能意味着你應該把內容移動到父模版中的一個 {% block %} 中。

  • 若是須要從父模板獲取塊的內容,block.super變量將完成此操做。若是要添加到父塊的內容中而不是徹底重寫父塊,則此選項很是有用。使用block.super插入的數據不會自動轉義),由於它已經在父模板中轉義

  • 爲了更好的可讀性,你也能夠給你的 {% endblock %} 標籤一個 名字 。例如:

    {% block content %}
    
    ...
    
    {% endblock content %}

    在大型模版中,這個方法幫你清楚的看到哪個  {% block %} 標籤被關閉了。

     

  • 不能在一個模版中定義多個相同名字的 block 標籤。
a
相關文章
相關標籤/搜索