一。代码布局(自定义的代码,放在哪里)
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