• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • Django開發入門——模板

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

    • 作為Web框架,Django提供了模板,可以很便利的動態生成HTML
    • 模板系統致力于表達外觀,而不是程序邏輯
    • 模板的設計實現了業務邏輯與顯示內容的分離,一個視圖可以使用任意一個模板,一個模板可以供多個視圖使用
    • 包含:HTML的靜態部分和動態插入內容部分
    • Django模板語言,簡寫DTL定義在django.template包中。
    • 在配置文件settings.py中定義了關于模板的值
      • DIRS定義了一個目錄列表,模板引擎安列表順序搜索這些目錄以查找模板源文件
      • APP_DIRS告訴模板引擎是否應該在每個已安裝的應用程序中查找模板
    • 常用方式:在項目的根目錄下創建templates目錄,設置DIRS值
    'DIRS': [os.path.join(BASE_DIR,'templates')],
    
    

    Python解釋器的工作原理
    轉到項目所在的目錄輸入python manage.py shell啟動交互界面。
    manage.py shell和python命令都可以啟動交互解釋器,但manage.py shell又一個重要的不同之處:在啟動解釋器之前,它告訴Django使用哪個配置文件。Django框架的大部分子系統,包括模板系統都依賴于配置文件;如果Django不知道使用哪個配置文件,這些系統將不能工作。Django搜索DJANGO_SETTINGS_MODULE環境變量,它被設置在settings.py中。當運行命令python manage.py shell,它會自動幫你處理DJANGO_SETTINGS_MODULE。
    創建模板對象
    直接導入django.template中的Template類,然后實例化。* 加載:根據所給定的標識找到模板然后預處理,通常將它編譯好放在內存中。

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

    得到一個template對象
    <django.template.base.Template object at 0x7f46ded2edd8>
    0x7f46ded2edd8為對象的ID
    當創建一個Template對象。模板系統在內部編譯這個模板到內部格式,并做優化做好渲染準備。
    模板渲染
    使用Context數據對模板進行插值并返回生成的字符串,一個context是一系列變量和它們值的集合。context在Django里表現為Context類。在django.template模塊里。它的構造函數帶有一個可選的參數,一個字典映射變量和它們的值。調用render()方法并傳遞context來填充。
    render()也稱快捷函數減少創建模板、渲染模板的重復代碼

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

    ‘My name is LiMing’
    Django模板系統的基本規則:

    • 寫模板
    • 創建Template對象
    • 創建Context
    • 調用render()方法
      同一模板,多個上下文
      一個模板對象可以渲染多個context,
    >>> from django.template import Template,Context
    >>> t=Template('Hello {{ name }}')
    >>> t.render(Context({'name':'John'}))
    'Hello John'
    >>> t.render(Context({'name':'liming'}))
    'Hello liming'
    
    

    像這樣只進行一次模板創建然后多次調用render()方法渲染會更高效。
    Django模板解析非常快捷。大部分的解析工作都是在后臺通過對簡短正則表達式一次性調用來完成。這和基于XML的模板引擎形成鮮明對比,那些引擎承擔了XML解析器的開銷,而且比Django模板渲染慢好幾個數量級。
    深度變量的查找
    模板系統可以處理更復雜的數據結構,如dict、list和自定義的對象,在Django模板中遍歷復雜數據結構的關鍵是句點字符(.)
    dict需要通過字典鍵訪問該字典的值,可使用一個句點:

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

    訪問對象的屬性

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

    通過實例變量加一點來訪問他的屬性,這個方法適用于任意對象。
    也可以引用對象的方法,但是只能調用不傳遞參數的方法。

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

    列表類型
    注意不允許負數列表索引如{{ items.-1}}這樣會報錯

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

    總結
    當模板系統在變量名中遇到點時,按照以下順序嘗試進行查找:

    • 字典類型查找
    • 屬性查找
    • 方法查找
    • 列表類型索引查找
      系統使用找到的第一個有效類型,這是以后短路邏輯。
      句點查找可以多級深度嵌套,如下面的例子中{{ 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'
    

    方法調用行為

    • 如果在方法查找過程中某方法拋出一個異常,如果該異常有一個silent_variable_failure屬性并且值為True,那么模板里指定變量會被置為空字符串。
    • 有些方法時有副作用的,如對象BankAccount有一個delete()方法。如果某個模板中包含了{{ account.delete }},而account又是BankAccount的一個實例,在這個模板載入時,account對象將被刪除。
      要防止這種情況發生,必須設置該方法的alter_data函數屬性:
    def delete(self):
    	delete.alters_data=True
    

    模板系統不會執行任何以該方式進行標記的方法。標記之后如果在有上面的情況,那么delete方法將不會被執行,將會靜靜地錯誤退出
    如何處理無效的變量
    默認情況下,如果一個變量不存在,模板系統會把它展示為空字符串,不做任何事情來表示失敗。
    基本的模板標簽和過濾器
    if/else
    和python中的功能差不多,所以就說一點不同之處。

    • {% if %}標簽不允許在同一個標簽同時使用and和or;如果非要使用這種功能可以將它移到模板之外處理然后以模板變量的形式傳入結果。或者使用嵌套的{% if %}

    • 沒有{% elif %}標簽
      for
      不同之處:

    • 這個標簽支持一個可選的{% empty %}分句,通過它我們可以定義當列表為空時的輸出內容。

    {% for i in athlete_list %}
    	pass
    {% empty %}
    	<p>The list already null</p>
    {% endfor %}
    
    • 不支持退出循環的操作

    • 不支持continue語句
      forloop模板變量
      可以提示循環進度信息

    屬性 功能
    forloop.counter 當前循環執行次數的整數計數器,從1開始
    forloop.counter0 當前循環執行次數的整數計數器,從0開始
    forloop.revcounter 循環剩余項個數的整形變量,以1作為結束索引
    forloop.revcounter0 循環剩余項個數的整形變量,以0作為結束索引
    forloop.first 一個布爾值,如果是第一次執行,那么為True
    forloop.last 一個布爾值,如果是最后一次執行,那么為True

    forloop變量僅僅能夠在循環中使用。在模板中碰到{% endfor %}標簽之后,forloop就不可訪問了。在一個{% for %}塊中已存在的變量會被移除,以避免forloop變量被覆蓋。Django會把這個變量移動到forloop.parentloop中。一旦早模板中定義了forloop這個變量,在{% for %}塊中它會在forloop.parentloop被重新命名。
    ifequal/ifnotequal
    {% ifequal %}標簽比較兩個值,當他們相等時。顯示在{% ifequal %}和{% endifequal %}值中所有的值。也支持可選的{% else %}標簽。只有模板變量,字符串,整數和小數可以作為{% ifequal %}的參數。其他類型如列表,字典都等都不能用在其中。
    注釋
    使用{# #}進行注釋,但是這種注釋不能跨越多行,可以用{% comment %} {% endcomment %} 進行多行注釋。
    過濾器
    過濾器在變量被顯示前修改它的值,使用管道復符,和Flask框架中的過濾器用法一樣。

    模板加載

    為了減少模板加載調用過程及模板本身的冗余(rong)的代碼,Django提供了以后宗使用方便且功能強大的API,用于從磁盤中加載模板。
    第一步:
    將模板的保存位置告訴框架。
    在配置文件settings.py中會看到

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
    	#該設置告訴Django的模板加載機制在那里查找模板
            'DIRS': [os.path.join(BASE_DIR,'templates')],
           ......
    

    第二步:
    視圖代碼,讓它使用Django模板加載功能而不是對模板路徑硬編碼。

    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()
        '''django.template.loader.get_template()
        這個函數以模板名為參數,在文件系統中找出模塊位置,
         打開并返回一個編譯好的Template對象'''
        t=get_template('current_datetime.html')
        html=t.render({'current_date':now})
        return HttpResponse(html)
    

    要確定某個模板文件在系統中的位置,get_template()方法會自動為你鏈接已經設置的’DIRS’: [os.path.join(BASE_DIR,‘templates’)],和你傳入該方法的模擬板名稱參數。如果找不到給名稱模板,將會引發一個TemplateDoesNotExist異常。如果你的配置文件中的DEBUG = True,則會在頁面看到調式的信息。使用python manage.py runserver來啟動服務器。
    這里寫圖片描述
    會告訴你找不到current_datetime.html這個文件,因為現在沒有創建。
    第三步:
    創建模板文件

    <h1>It is now {{ current_date }}.</h1>
    

    運行結果
    這里寫圖片描述
    render_to_response()
    Django提供了一個捷徑,讓你一次性的載入某個模板文件,渲染它,然后將此作為HttpResponse返回。
    render_to_response()的第一個參數必須是要使用的模版名稱。如果第要給丁第二個參數,那么該參數必須是為該模板創建Context時所用的字典。如果不提供第二個參數,那么render_to_response()使用一個空字典。

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

    locals()技巧
    他返回的字典對所有局部變量的名稱與值進行映射。沒有像之前那樣傳入Context字典,而時傳入了locals()的值,它囊括了函數執行到該時間點是所定義的一切變量。但是并沒有帶來多大的改進。

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

    get_template()
    把模板存放于模板目錄的子目錄;如將模板放在templates的dateapp子目錄下。

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

    對子目錄樹的深度沒有限制。
    include模板標簽
    {% include %}該標簽允許在模板中包含其他模版的內容。標簽參數使所要包含模板的名稱,可以是一個變量,也可以是字符串。
    {% include current_datetime.html %}
    包含了current_datetime.html模板。

    模板繼承

    雖然Django支持{% include %}方法,但是首選方法是使用模板繼承方法。本質上來說,模板繼承就是縣構造一個基礎框架模板,而后在其子模板中對它所包含站點公用你分和定義塊進行重載。

    • 創建基礎框架,并在基礎框架使用{% block 了可以繼承的部分名字 %}來確定哪一部分可以繼承,重載。

    • 繼承模板,{% extends “繼承的模板名” %}
      模板繼承的訣竅

    • 如果在模板中使用{% extends %},必須保證其為模板中的第一個模板標記。否則模板繼承不起作用。

    • 一般來說,基礎模版中的{% block %}越多越好;

    • 如果發現在多個模板之間拷貝代碼,應該考慮將這段代碼放到基礎模板中

    • 不允許在同一模板中定義多個同名的{% block %},因為block標簽的工作方式式雙向的。block標簽不僅挖了一個要填的坑,也定義了在父類模板中這個坑所填的內容。如果重名,父模板將無從知道要使用哪個塊的內容;

    • {% extends %}對傳入模版名稱使用的加載方法和get_template()相同;

    • {% extends %}的參數也可以是變量。

    高級模板應用

    RequestContext和Context處理器
    RequestContext默認的在模板context中加入了一些變量,如HttpRequest對象或當前登陸用戶的相關信息。當你不想在一系列模板中都明確指定一些相同變量時,應該使用RequestContext。創建RequestContext和Context處理器就是為了消去冗余的代碼。Context處理器允許你設置一些變量,他們會在每個context中自動被設置好,而不必每次調用render_to_reaponse()時都指定。

    from django.template import loader,RequestContext
    
    
    #這是一個context處理器,接收一個HttpResponse對象
    #返回一個字典,包含可以在模板中使用的變量
    def custom_proc(request):
        return {
            'app':'My app',
            'user':request.user,
            'ip_adress':request.META['REMOTE_ADDR']
        }
    
    def view_1(request):
        t=loader.get_template('template1.html')
        c=RequestContext(request,{'message':'i am view 1.'},
                         processors=[custom_proc])
    
        return t.render(c)
    
    
    
    def view_2(request):
        t=loader.get_template('template2.html')
        c=RequestContext(request,{'message':'i am view 2.'},
                         processors=[custom_proc])
    
        return t.render(c)
    

    用RequestContext代替了Context。與Context對象創建的不同:
    1.RequestContext的第一個參數需要傳遞一個HttpResponse對象
    2.RequestContext有一個可選參數processors,這好似一個包含context處理器函數的列表或元組。
    render_to_response可以簡化調用loader.get_template()然后創建一個context對象,最后在調用模板對象render()的過程。

    def view_1(request):
        return render_to_response('template1.html',
                                  {'message':'i am view 1'},
                                  context_instance=RequestContext(request,processors=[custom_proc]))
    

    以代碼冗余的代價消除了數據上的冗余。
    Django因此提供了對全局context處理器的支持。

    'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                   
                ],
    

    context_processors指定的那些總是默認被使用。這樣就省去了每次都要指定processors的麻煩。這個設置項是一個可調用的元組,其中每個函數使用了和custom_proc相同的接口。每個處理器將會按照順序應用。如果同名,后面的會覆蓋前面的。
    django.core.context_processors.auth
    如果 TEMPLATE_CONTEXT_PROCESSORS 包含了這個處理器,那么每個 RequestContext 將包含這些變量:

    • user :一個 django.contrib.auth.models.User 實例,描述了當前登錄用戶(或者一個 AnonymousUser 實
      例,如果客戶端沒有登錄)。

    • messages :一個當前登錄用戶的消息列表(字符串)。 在后臺,對每一個請求,這個變量都調用

    • request.user.get_and_delete_messages() 方法。 這個方法收集用戶的消息然后把它們從數據庫中刪除。

    • perms : django.core.context_processors.PermWrapper 的一個實例,包含了當前登錄用戶有哪些權限。
      django.core.context_processors.debug
      這個處理器把調試信息發送到模板層。 如果 TEMPLATE_CONTEXT_PROCESSORS 包含這個處理器,每一
      個 RequestContext 將包含這些變量:

    • debug :你設置的 DEBUG 的值( True 或 False )。你可以在模板里面用這個變量測試是否處在debug模
      式下。

    • sql_queries :包含類似于 {‘sql’: ..., ‘time’: 的字典的一個列表, 記錄了這個請求期間的每個SQL查詢以及查詢所耗費的時間。 這個列表是按照請求順序進行排列的。

    • System Message: WARNING/2 ( , line 315); backlink
      Inline literal start-string without end-string.
      由于調試信息比較敏感,所以這個context處理器只有當同時滿足下面兩個條件的時候才有效:

    • DEBUG 參數設置為 True 。

    • 請求的ip應該包含在 INTERNAL_IPS 的設置里面。
      django.core.context_processors.request
      如果啟用這個處理器,每個 RequestContext 將包含變量 request , 也就是當前的 HttpRequest 對象。 注意這
      個處理器默認是不啟用的,你需要**它。
      寫Context處理器的一些建議
      編寫處理器的一些建議:

    • 使每個context處理器完成盡可能小的功能。 使用多個處理器是很容易的,所以你可以根據邏輯塊來分解功能以便將來復用。

    • 要注意 TEMPLATE_CONTEXT_PROCESSORS 里的context processor 將會在基于這個settings.py的 每個 模板中有效,所以變量的命名不要和模板的變量沖突。 變量名是大小寫敏感的,所以processor的變量全用大寫是個不錯的主意。
      不論它們存放在哪個物理路徑下,只要在你的Python搜索路徑中,你就可以在
      TEMPLATE_CONTEXT_PROCESSORS 設置里指向它們。 建議你把它們放在應用或者工程目錄下名為context_processors.py 的文件里
      html自動轉意
      從模板生成html的時候,總是有一個風險——變量包了含會影響結果html的字符。用戶提交的數據不應該被盲目信任,直接插入到你的頁面中。因為一個潛在的惡意的用戶能夠利用這類漏洞做壞事。 這類漏洞稱為被跨域腳本 (XSS) 攻擊。
      在django里默認情況下,每一個模板自動轉意每一個變量標簽的輸出。這個行為默認是開啟的。
      如何關閉?

    • 對于單獨的變量:

    This will not be escaped: {{ data|safe }}
    
    • 對于模板塊:
    {% autoescape off %}
    Hello {{ name }}
    {% endautoescape %}
    

    autoescape 標簽有兩個參數on和off 有時,你可能想阻止一部分自動轉意,對另一部分自動轉意。

    {% autoescape off %}
    This will not be auto‐escaped: {{ data }}.
    Nor this: {{ other_data }}
    {% autoescape on %}
    Auto‐escaping applies again: {{ name }}
    {% endautoescape %}
    {% endautoescape %}
    

    auto-escaping 標簽的作用域不僅可以影響到當前模板還可以通過include標簽作用到其他標簽,就像block標簽一樣,繼承關閉該功能的模板,默認也是關閉的。
    模板加載的內幕
    一般說來,你會把模板以文件的方式存儲在文件系統中,但是你也可以使用自定義的 template loaders 從其他來源加載模板。
    Django有兩種方法加載模板:

    • django.template.loader.get_template(template_name) : get_template 根據給定的模板名稱返回一個已編譯的模板(一個 Template 對象)。 如果模板不存在,就觸發 TemplateDoesNotExist 的異常。

    • django.template.loader.select_template(template_name_list) : select_template 很像get_template ,不過它是以模板名稱的列表作為參數的。 它會返回列表中存在的第一個模板。 如果模板都不存在,將會觸發 TemplateDoesNotExist 異常。
      一些加載器默認被禁用,但是你可以通過編輯 TEMPLATE_LOADERS 設置來**它們。 TEMPLATE_LOADERS 應當是一個字符串的元組,其中每個字符串都表示一個模板加載器。

    • django.template.loaders.filesystem.load_template_source : 這個加載器根據 TEMPLATE_DIRS 的設置從文件系統加載模板。它默認是可用的。

    • django.template.loaders.app_directories.load_template_source : 這個加 載器從文件系統上的Django
      應用中加載模板。 對 INSTALLED_APPS 中的每個應用,這個加載器會查找 templates 子目錄。 如果這個目錄存在,Django就在那里尋找模板,這意味著你可以把模板和你的應用一起保存,從而使得Django應用更容易和默認模板一起發布,加載器在首次被導入的時候會執行一個優化: 它會緩存一個列表,這個列表包含了 INSTALLED_APPS中帶有 templates 子目錄的包。
      擴展模板系統

    • 創建一個模板庫
      1.決定模板庫的位置
      2.創建templatetags目錄,包含**init.py**文件和一個用來存放自定義標簽/過濾器的文件,第二個文件名字將用來加載標簽。
      如果你的第二個文件叫poll_extras.py,那么在模板中寫入

    {% load poll_extras %}
    

    {% load %}標簽交叉INSTALLED_APPS中的這是,僅允許加載已安裝的Django應用程序中的模板庫。{% load %}語句使用過指定python模塊名而不是應用名來加載標簽/過濾器。
    作為一個合法的標簽庫,模塊需要一個名為register的模塊變量,它是template.Library的實例,是所有注冊標簽和過濾器的數據結構。

    from django import template
    
    register=template.Library()
    

    創建過濾器

    **def cut(value,arg):
        return value.replace(arg,'')
    
    
    def lower(value):
        return value.lower()
    
    
    #注冊過濾器,需要傳入兩個參數(過濾器的名稱,過濾器函數本身)
    register.filter('cut',cut)
    register.filter('lower',lower)**
    
    k#使用裝飾器
    @register.filter(name='cut')
    def cut(value,arg):
        return value.replace(arg,'')
    
    @register.filter(name='lower')
    def lower(value):
        return value.lower()
    

    自定義模板標簽
    當Django編譯一個模板時,它的原始模板分成一個個節點,每個節點艘時django.template.Node的一個實例,并且具備render()方法。于是一個已編譯模板就是節點對象的一個列表。

    Hello,{{ person.name }}
    
    {%  ifequal name.birthday today %}
        Happy birthday!
    {% else %}
        Be your to come back on your birthday
    {% endifequal %}
    

    編譯上面的模板,被變異的模板表現為節點列表的形式:

    • 文本節點:‘Hello,’
    • 變量節點:preson.name
    • 文本節點:‘\n\n’
    • Ifqual節點:name.birthday和today
      當你調用一個已編譯的模板的render()方法時,模板就會用給定的context來調用每個在它的節點列表上的所有節點的render()方法。這些渲染的結果合并起來形成模板的輸出。因此,要子定義模板標簽,你需要指明原始模板標簽如何轉換成節點和節點的render()方法完成的功能。
      編寫編譯函數
      當遇到一個標簽模板時,模板解釋器就會把標簽包含的內容,以及模板結合四器自己作為參數嗲用一個python函數,這個函數負責返回一個和房前模板標簽內容相對應的節點的實例。
      寫一個顯示當前日期模板標簽
    <p>The time is {% current_time "%Y‐%m‐%d %I:%M %p" %}.</p>
    
    #每個標簽編譯函數有兩個參數parser 和 token,parser時模板解析器對象
    #token是正在被解析的語句
    def do_current_time(parser,token):
        try:
            #token.split_contents()按空格拆分參數同時保證引號中的字符串不拆分
            #不使用token.contents.split()是因為它不健壯,它值是簡單的按照所有
            # 空格進行拆分,包括那些引號因起來的字符串中的空格
            #token.contents是包含標簽原始內容的字符串
            tag_name,format_string=token.split_contents()
        except ValueError:
            # token.split_contents()[0]總是記錄標簽的名字,就標簽沒有任何參數
            msg='%r tag requires a single argument' %token.split_contents()[0]
            raise template.TemplateSyntaxError(msg)
        #CurrentTimeNode包含了節點需要知道的關于這個標簽的全部信息。
        return CurrentTimeNode(format_string[1:-1])
    

    編寫模板節點

    import datetime
    
    #編寫模板節點
    class CurrentTimeNode(template.Node):
        def __init__(self,format_string):
            self.format_string=str(format_string)
    
        def render(self, context):
            now=datetime.datetime.now()
            return now.strftime((self.format_string))
    

    注冊標簽

    register.filter('current_time',do_current_time())
    

    在上下文中設置變量
    要早上下文中設置變量,在render()函數的context對象上使用字典賦值。

    class CurrentTimeNode2(template.Node):
        def __init__(self,format_string):
            self.format_string=str(format_string)
    
        def render(self, context):
            now=datetime.datetime.now()
            context['current_time']=now.strftime(self.format_string)
            return ''
    

    render()應當總是返回一個字符串,所以如果模板標簽只是要設置變量,render()就要返回一個空字符串。
    但是變量名current_time是硬編碼的,這意味著你必須確定你的模板在其他地方都用不到{{ current_time }},因為{% current_time2 %}會盲目覆蓋變量值。

    import re
    
    class CurrentTimeNode3(template.Node):
    
        def __init__(self,format_string,var_name):
    
            self.format_string=str(format_string)
            self.var_name=var_name
    
        def render(self, context):
            now=datetime.datetime.now()
            context['current_time']=now.strftime(self.format_string)
            return ''
    
    def do_current_time(parser,token):
        try:
            tag_name,arg=token.split_contents(None,1)
        except ValueError:
            msg='%r tag requires a single argument' %token.split_contents()[0]
            raise template.TemplateSyntaxError(msg)
    
    
        m=re.search(r'(.*?) as (\w+)',arg)
    
        if m:
            fmt,var_name=m.groups()
        else:
            msg='%r tag had invalid argument' %tag_name
            raise template.TemplateSyntaxError(msg)
        if not (fmt[0] ==fmt[-1] and fmt[0] in ('"',"'")):
            msg='%r tags argument should be in quotes' %(tag_name)
            raise template.TemplateSyntaxError(msg)
    
        #現在把字符串和變量名傳遞給CurrentTimeNode3
        return CurrentTimeNode(fmt[1:-1],var_name)
    
    
    版權聲明:本文為mashaokang1314原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/mashaokang1314/article/details/81484489

    智能推薦

    Django 模板

    文章目錄 Django 模板 模板應用實例 Django 模板標簽 變量 列表 字典 過濾器 if/else 標簽 for 標簽 ifequal/ifnotequal 標簽 注釋標簽 include 標簽 csrf_token 自定義標簽和過濾器 settings.py 配置文件 配置靜態文件 模板繼承 父模板 子模板 Django 模板 在上一章節中我們使用 django.http.HttpRe...

    Django模板

    靜態目錄 配置靜態目錄 STATIC_URL配置的靜態目錄位于項目根目錄下的static文件夾,用于保存項目公共的靜態資源。 STATICFILES_DIRS配置的是項目應用的靜態目錄,位于應用根目錄下的static文件夾,用于保存不同應用的靜態資源。 使用靜態目錄 配置靜態目錄后可在模板中使用配置靜態目錄替代文件路徑 模板中加載應用的靜態資源 模板引用應用靜態資源 模板中直接定義定義靜態資源路徑...

    Django 模板

    0x01 概念 模板是一個文本,用于分離文檔的表現形式和內容。 0x02 模板應用實例 0x03 Django 模板標簽 變量 HelloWorld/HelloWorld/views.py 文件代碼: 列表 templates 中的 runoob.html中,可以用 . 索引下標取出對應的元素。 HelloWorld/HelloWorld/views.py 文件代碼: HelloWorld/tem...

    HTML中常用操作關于:頁面跳轉,空格

    1.頁面跳轉 2.空格的代替符...

    freemarker + ItextRender 根據模板生成PDF文件

    1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...

    猜你喜歡

    電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!

    Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...

    requests實現全自動PPT模板

    http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...

    Linux C系統編程-線程互斥鎖(四)

    互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...

    統計學習方法 - 樸素貝葉斯

    引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...

    精品国产乱码久久久久久蜜桃不卡