一。代码布局(自定义的代码,放在哪里)
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=Library()
4.(1)使用filter方法:在定义好的实现过滤器功能的函数下面通过这个实例的filter方法去把之前定义的函数注册为一个过滤器register.filter(函数名) ---注意函数名不要带括号,这里是为了把函数体传出去
函数名是必须有的,自定义name可以没有。
注意filter方法的参数,这里不给过滤器起名定义name,直接用函数名,就不要用关键词参数,直接传位置参数函数名,
如果用关键字参数filter_func=函数名,就必须再用name=过滤器名加个name关键字参数,或者两个参数name和filter_func都不用关键字参数,作为位置参数的话注意如有name,则name参数在前
(2)使用装饰器:直接在实现过滤器的功能的函数上加个装饰器@register.filter(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):
函数体...
5)模板中使用:这里有两个步骤,
- 先要load一下,通过python模块名{% load 模块名 %}
- 在需要使用过滤器的模板变量里使用{{模板变量|过滤名(没起名的就是过滤器函数名):参数arg}} --#这里参数如果是字符串的,要加引号
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--登记,注册)接收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并用一个变量接收这个实例,然后注册分为两种方法,直接调用和当成装饰器
(1)调用实例变量的.simple_tag方法:register.simple_tag(name,simple_tag_func)
(2) 把实例变量的.simple_tag方法作为装饰器给功能函数加上,括号里可以定义name也可以不定义
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里依次取值
2,注册:回到模块中,还是用的导入模块django.template import Library,实例化Library并用一个变量接收这个实例。
给定义好的函数加上装饰器@实例变量名.inclusion_tag() 这个装饰器需要参数,这个参数是个模板的名称要加引号,
这个模板是刚才定义的用于在其他模板中展示的模板的名称,‘templates下的app名/这个模板所在的文件夹名/模板名’
3.使用包含标签:
(1)回到视图函数中,添加想展示的内容的参数
(2)在需要插入包含标签的模板,指定位置插入模板标签{% 函数名 传递给函数的模板变量名 %} 和include一样,这是单标签
4,添加样式:(1)模块中的函数里多接收一个参数style,return的字典里加上键值对'style':style
(2)给展示在其他模板中的模板添加样式,希望可以选择样式,可以多写几种
(3)需要插入包含标签的模板中,使用的时候多加一个参数,style参数,和前边的模板变量空格分开,可以选择前面在展示用的模板里添加的几种样式名字,引号括起来
5.也可以拿到视图函数中的context:
(1)模块中函数的装饰器加上takes_context=true参数,
(2)传入给函数的参数加上context,必须是第一个参数
6.使用包含标签时候,传参数的时候,也可以用关键字参数
- 简单标签是模块中函数返回什么就渲染什么,比较直接
-包含标签是模块中返回的传给一个模块页面进行渲染,再把渲染结果返回给插入这个包含标签的模板页面
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>
最后结果都是