自定義模板過濾器和自定義模板標籤

一。代碼佈局(自定義的代碼,放在哪裏)
1. 某個app特有的
    1)-app 目錄下,templatetags 文件夾--這個文件夾名是固定的,寫別的名字識別不了,這個文件夾是python的一個包,裏邊須要有一個__init__.py文件
        在pycharm中app下,能夠右鍵New Package建立一個包
    -再到 templatetags 文件夾下建立python模塊(py文件)模塊存放自定義的模板標籤和過濾器,django根據templatetags根據裏邊的python模塊來引用
2. 定義複用,不少app公用的
    -建立一個新的app,將他們定義在新的app中,在INSTALL_APPS
    註冊,而後就能夠應用

二。自定義過濾器和模板標籤
1.自定義模板過濾器:
    1)舉例:(1)描述:視圖函數中學生信息列表裏邊爲每一個學生創建的我的信息字典,裏邊的sex這個鍵,它存儲的值通常是1或0表明男女,而不是以前定義的字符串男或女,如何渲染到模板中的時候經過過濾器把1或0這樣的數字變成男或者女
              (特別提示:注意模板過濾器改變的是視圖函數中傳給模板的參數在模板中渲染出來的效果,參數自己沒有變,過濾器變了,只是影響了渲染出來的效果,而非參數自己,
                  而若是咱們改變視圖函數中的參數,則在模板中全部涉及到該參數的模板標籤,都須要考慮是否收到影響,收到影響的模板標籤應該根據視圖函數中的參數值做出針對性的改變
                  好比說視圖函數中的男女字符串變成1或0,模板中根據學生信息的性別判斷應該在表格中該學生的行顯示顏色的模板標籤的判斷語句應該變成==1和==0,以前的=='男'和=='女'的條件語句已經失效了)
                (2)步驟:1.app中的templatetags文件夾中,新建一個.py文件,名字任意取,這個就做爲一個模塊,用這個過濾器的時候就能夠經過它的名字進行導入
                          2.上面定義的模塊中,定義一個函數,接收2個參數value和arg,其中arg是默認參數,函數中定義一個字典,返回字典[arg][value]
                          3.模塊中導入Library類:from django.template import Library,而後實例化Library,用一個變量register接收他 ,變量名必須是固定的名稱register ,register=Library(),下面的自定義模板標籤(簡單標籤和包含標籤)註冊的時候也是這樣
                          4.(1)使用filter方法:在定義好的實現過濾器功能的函數下面經過這個實例的filter方法去把以前定義的函數註冊爲一個過濾器register.filter(函數名)    ---注意函數名不要帶括號,這裏是爲了把函數體傳出去
                      函數名是必須有的,自定義name能夠沒有。
                      注意filter方法的參數,這裏不給過濾器起名定義name,直接用函數名,就不要用關鍵詞參數,直接傳位置參數函數名,
                      若是用關鍵字參數filter_func=函數名,就必須再用name=過濾器名加個name關鍵字參數,或者兩個參數name和filter_func都不用關鍵字參數,做爲位置參數的話注意若有name,則name參數在前
                    (2)使用裝飾器:直接在實現過濾器的功能的函數上加個裝飾器@register.filter(name)   html

              --#這裏django作了優化(裝飾器能夠不加括號的原理見最下面),能夠沒有括號,有括號的話能夠不加name空着,也能夠加name,可是加了在模板中使用這個過濾器就要用name而不是函數名
                        注意起了名模板裏用這個過濾器的時候就必須用名字不能再用函數名    
                          5.註冊過過濾器後最好從新run一下,不從新運行就在模板中使用,而後刷新網頁查看,會報錯,顯示過濾器還沒註冊,由於通常的已存在的文件上的修改可以自動上傳,若是新建了文件或者文件夾,則須要從新運行才能讀出來
                          6.在模板中使用,首先經過模塊名load,若是是定義在本app目錄下的過濾器,直接在模板中{% load 模塊名 %} load完就能夠在當前模板去使用這個過濾器
                          7.在想使用過濾器的模板變量中,和使用其餘默認模板過濾器同樣{{變量名|過濾器名(沒起名的就是過濾器函數名):參數}}   --#參數是字符串格式的就要用引號括起來
                      注意過濾器模板中,註冊的時候若是給了name,模板中使用的時候就要用過濾器名字,不能再直接用過濾器方法名了
    2)模板過濾器是什麼
        -本質就是函數,一個或兩個參數
            - 第一個參數,是傳遞進來的模板變量(不必定是字符串)
            - 第二個參數,普通的參數,也能夠是默認,也能夠不要
        其實就是個函數,沒有什麼不一樣
    3) 定義很是簡單,就是寫一個函數
    
    4)註冊:首先模塊中要導入Library類 :from django.template import Library,而後實例化這個類,把這個實例賦值給一個變量
        1.調用Library 實例的 filter 方法,
            filter 有兩個參數:注意在django.template的Library.py裏邊定義的filter方法,參數位置name在前,filter_func在後,若調用時傳參用位置參數也要name在前
                - name 過濾器的名稱,是個字符串,能夠不寫,默認
                    使用方法名做爲過濾器的名稱
                - filter_func 定義的過濾器的函數
        2.經過裝飾器,能夠直接給過濾器函數加個裝飾器:Library類的實例的filter方法
            @register.filter(name)   --#必須有括號,能夠不加name空着,也能夠加name,可是加了在模板中使用這個過濾器就要用name而不是函數名
            def func(value,arg):
                 函數體...前端

from django.template import Library
register = Library()
@register.filter('male')
def to_male(value, arg='zh'):
    map = {
        'zh': ('', ''),
        'en': ('female', 'male'),
    }
    return map[arg][value]
# register.filter(filter_func=to_male, name='sex_is')

    5)模板中使用:這裏有兩個步驟,
        - 先要load一下,經過python模塊名{% load 模塊名 %}
        - 在須要使用過濾器的模板變量裏使用{{模板變量|過濾名(沒起名的就是過濾器函數名):參數arg}}   --#這裏參數若是是字符串的,要加引號python

{% load customer_filters %}
 {% for stu in students %}
         <td>{{stu.sex|male:'en'}}</td>

2.自定義模板標籤--模板標籤,實現任意邏輯,django提供的模板標籤能夠實現不少功能,但仍是有些狀況實現不了,django提供了不少快捷方式,使咱們能編寫大多數類型的標籤,去自定義模板標籤,實現大多數功能
    1)學習思路:(1)快捷方式(2)如何經過這些快捷方式編寫自定義功能的模板標籤(3)推薦 讀官方文檔
    2)分類
        - 簡單標籤 --許多的模板標籤接受許多的參數(好比字符串或模板變量等),並根據輸入的參數和外部的信息進行處理,而後返回結果,例如url模板標籤,接收一個字符串,接收一個模板變量,把這些信息加工處理以後輸出一個須要的結果
            django經過template.Library類中的simple_tag幫助函數(快捷方式)來建立:django.template.Library.simple_tag()
            1. 建立: 新建模塊,定義功能函數:
                普通的python函數
            2.註冊:導入Library類:django.template import Library,定義變量register(register--登記,註冊)接收Library類的實例,而後兩種方法,直接調用simple
                1).  即直接調用simple_tag方法,能夠傳兩個參數,第一個是給這個模板標籤自定義的name,第二個是功能函數的函數名--不要加括號
                2).裝飾器:把實例變量的simple_tag方法做爲自定義的功能函數的裝飾器,和上面的自定義模板過濾器一個道理,既然是裝飾器,參數就不須要傳功能函數的函數名了,起名字填上,不起名字括號空着就能夠
                3)新建了customer_tags.py並註冊了自定義標籤以後,應該從新run一下項目,否則容易報錯
            3. 引用  模板中首先導入自定義標籤模塊{% load 模塊名 %}
                在模板指定位置插入{% 自定義tag_name(沒有定義標籤name則用功能函數名) 參數 %}
            4.上下文變量(views中render傳遞到模板中的那個context)
                    只須要在simple_tag 中,設置參數take_context=True     (注意在simple_tag方法定義時,位置參數順序分別是func,take_context,name)
                    自定義的標籤函數的第一個參數必定是 context,也就是是說def func(context,arg):    (這種狀況下必須有context,名字不能更改,並且必須是第一個參數)
            5.舉例:自定義標籤實現輸出當前時間,運行傳一個格式化的字符串得到咱們須要的格式
                1)新建模塊:仍是在app文件夾中的templatetags文件夾裏,新建py文件,本身起個不會引起衝突的名字
                2)定義功能函數:定義一個實現想要的功能的函數,好比本例中py文件先from datetime import datetime
                    而後定義函數def current_time(format_str):
                                return datetime.now().strftime(format_str)
                3)註冊:首先導入模塊django.template import Library,實例化Library並用一個變量register接收這個實例,而後註冊分爲兩種方法,直接調用和當成裝飾器
                    (1)調用實例變量的.simple_tag方法:register.simple_tag(name,simple_tag_func)
                      (2) 把實例變量的.simple_tag方法做爲裝飾器給功能函數加上,括號裏能夠定義name也能夠不定義django

視圖函數中:app

format_str = '%Y-%m-%d %H:%M:%S'
    return render(request, 'teacher/html_teacher_index.html', context={
        'students': students,
        'format_str': format_str,
        'meta': arg['_meta']
    })

模塊中函數

from datetime import datetime
from django.template import Library

register = Library()
def current_time(context):
    return datetime.now().strftime(context['format_str'])
register.simple_tag(current_time,takes_context=True, name='current')
 <h1>當前時間是:{% current %}</h1>

                4)在模板中引用:首先模板裏必須經過load模板標籤引入自定義標籤模塊:{% load customer_tags %}
                5) 模板中指定位置插入{% current '%Y-%m-%d %H:%M:%S' %}
                6)若是模板標籤中想使用視圖函數中的變量,回到customer_tags.py模塊,
                    (1)在simple_tag方法里加上參數take_context=True
                    (2)自定義的功能函數,定義函數時加一個參數context(名字不能更改),它必須放在參數第一個,
                        def current_time(context):
                            return datetime.now().strftime(context['format_str'])   
                            ---注意此時的format_str不是自定義模板標籤所引用的模塊裏自定義函數的參數,
                                  而是視圖函數return 返回的context參數裏的鍵,它的值則是視圖函數裏面定義的變量,一個格式化的時間字符串
                    (3)模板文件的標籤中,記得把相應的參數去掉,由於這個參數再也不是從模板文件中傳的,而是從視圖函數中傳的    
        - 包含標籤 --也叫嵌套標籤等,經過渲染另一個模板來展現數據,能夠簡單理解爲include模板標籤,用於把某些數據渲染成固定的樣式
            django.template.Library.inclusion_tag()
            1.定義:(1)在模塊中,仍是模塊中定義一個新函數,這個函數接受調用時傳遞的模板變量, 再把它放到字典裏return出去
                        (2)定義新模板(也能夠在模板目錄下新建目錄放一些用於模板標籤的須要展現在其餘模板裏的模板)
                    這個模板裏把其餘的內容刪掉,只寫須要渲染的部分便可,這個模板裏添加for模板標籤,從以前模塊中定義的函數return出去的字典的key裏依次取值佈局

{% if style == 'button' %}
    <div class="list-group">
        {% for l in ls %}
            <button type="button" class="list-group-item">{{l}}</button>
        {% endfor %}
    </div>
{% elif style == 'link' %}
    <div class="list-group">
        {% for l in ls %}
            <a href="#" class="list-group-item active">{{l}}</a>
        {% endfor %}
    </div>
{% else %}
    <ul class="list-group">
        {% for l in ls %}
            <li class="list-group-item">{{l}}</li>
        {% endfor %}
    </ul>
{% endif %}

            2,註冊:回到模塊中,仍是用的導入模塊django.template import Library,實例化Library並用一個變量register接收這個實例。
                給定義好的函數加上裝飾器@實例變量名.inclusion_tag() 這個裝飾器須要參數,這個參數是個模板的名稱要加引號,
                這個模板是剛纔定義的用於在其餘模板中展現的模板的名稱,‘templates下的app名/這個模板所在的文件夾名/模板名’學習

@register.inclusion_tag('teacher/show_list_as_url.html')
def show_list_as_url(value,style):  #這個value是前端傳過來的模板變量
    return {"ls": value, 'style': style}

            3.使用包含標籤:
                (1)回到視圖函數中,添加想展現的內容的參數
                (2)在須要插入包含標籤的模板,指定位置插入模板標籤{% 函數名 傳遞給函數的模板變量名 %} 和include同樣,這是單標籤優化

 <td>{% show_list_as_url stu.course 'base' %}</td>

            4,添加樣式:(1)模塊中的函數裏多接收一個參數style,return的字典里加上鍵值對'style':style
                (2)給展現在其餘模板中的模板添加樣式,但願能夠選擇樣式,能夠多寫幾種
                (3)須要插入包含標籤的模板中,使用的時候多加一個參數,style參數,和前邊的模板變量空格分開,能夠選擇前面在展現用的模板裏添加的幾種樣式名字,引號括起來
            5.也能夠拿到視圖函數中的context:
                (1)模塊中函數的裝飾器加上takes_context=true參數,
                (2)傳入給函數的參數加上context,必須是第一個參數
            6.使用包含標籤時候,傳參數的時候,也能夠用關鍵字參數
        - 簡單標籤是模塊中函數返回什麼就渲染什麼,比較直接
        -包含標籤是模塊中返回的傳給一個模塊頁面進行渲染,再把渲染結果返回給插入這個包含標籤的模板頁面url


3 模板變量補充:視圖函數中若是某變量中帶有前邊帶_的鍵或屬性或方法,把他傳到前端,前端是接受不到這樣帶下劃線的鍵或屬性或方法的,
        若是非要把這樣帶下劃線的鍵或屬性或方法傳給模板,能夠在return中的context參數中專門拿一個鍵把他放進去,
        或者在視圖函數中把他用其餘變量接收,再把接收他的變量放context中return出去

這樣是錯誤的

    arg = {
        '_meta': "ewreryr",
    }
    format_str = '%Y-%m-%d %H:%M:%S'
    return render(request, 'teacher/html_teacher_index.html', context={
        'students': students,
        'format_str': format_str,
        'arg': arg
    })
   <h1>{{arg._meta}}</h1>

結果會報錯

好比視圖函數中

 arg = {
        '_meta': "ewreryr",
    }
return render(request, 'teacher/html_teacher_index.html', context={
        'meta': arg['_meta']
    })

或者

    arg = {
        '_meta': "ewreryr",
    }
    meta = arg['_meta']
    format_str = '%Y-%m-%d %H:%M:%S'
    return render(request, 'teacher/html_teacher_index.html', context={
        'students': students,
        'format_str': format_str,
        'meta': meta
    })
<h1>{{meta}}</h1>

最後結果都是

 

*****裝飾器能夠不加括號的原理:

def log(func=None):
    def wrapper(fun):
        def inner(*args,**kwargs):
    print('do something before do fun')
    res = fun(*args,**kwargs)
    print('do something after do fun')
    return res
        return inner
    if func is None:
        return wrapper
    elif callable(func):
        return wrapper(func)

這樣把log函數用做其餘函數的裝飾器時,log能夠加括號也能夠不加:

@log
def my_func():
    print('I am my_func')

1)log不加()等價於my_func = log(my_func)2)作裝飾器時候log加():@log()def my_func():    ……至關於my_func = log()(my_func)兩種方法都是指向wrapper裏的inner

相關文章
相關標籤/搜索