django的templatetags
- 创建tag方式,首先在需要使用tag的app下创建一个templatetags的python包,
- 然后在包里创建一个tag模块,例如hellotag.py
from django import template
register = template.Library() # 注意,这里的变量名一定是register,可不是任意的名称
@ register.simple_tag
def hello(*args):
return "hello " + " ".join(str(args))
然后就可以在需要使用tag的页面引用自定义tag了
{% load hellotag %}
{% hello "world !" %}
然后需要重启Django服务,再通过页面测试结果
- 为什么只能是register,因为Django源码里就是这么解析的
def get_package_libraries(pkg):
"""
Recursively yield template tag libraries defined in submodules of a
package.
"""
for entry in walk_packages(pkg.__path__, pkg.__name__ + '.'):
try:
module = import_module(entry[1])
except ImportError as e:
raise InvalidTemplateLibrary(
"Invalid template library specified. ImportError raised when "
"trying to load '%s': %s" % (entry[1], e)
)
if hasattr(module, 'register'):
yield entry[1]
- 为什么需要重启tag才生效?因为Django在第一次启动时就将一些不易变动的模块代码使用缓存方式的装饰器将这些模块缓存起来了,这样方便加快响应速度,而不是每次返回给用户页面时都重新加载一次tag模块,那样每个用户每访问一个页面,都重新导入一次响应肯定会很慢
- Django默认会加载以下tag模块
'django.template.defaulttags',
'django.template.defaultfilters',
'django.template.loader_tags',
通过settings指定tag模块
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'cloud.api.libs.context_processors.common_processor',
],
'autoescape': True,
'debug': settings.DEBUG, # 该值就是我们自定义的settings模块的debug变量值。
'file_charset': settings.FILE_CHARSET, # 这个settings是从全局的Django settings导入的,默认为"utf-8"
'libraries': {} # 这里是字典类型的tag模块名称,例如:项目cloud目录下有一个show.py tag模块,那么完整的模块路径为cloud.show,定义到这个字典的格式为{'show': 'cloud.show'}
},
},
]
注意: TEMPLATES这个列表里的每一个字典元素的key只能是这几个,不能多,也不能少,OPTIONS这个key对应的字典元素里面的key,除了context_processors
以外,其余值都可以不写,默认自带的配置已经有context_processors
了,如果需要自定义其它位置的tag模块,可以添加libraries
这个选项
- render处理过程
# view方法通过render方法返回模版,如return render(request, 'index.html', context=None, content_type=None, status=200, using=None)
# 首先调用render方法,传入参数
# render再调用render_to_string方法去获取模版,并渲染模版,返回一个字符串
# 我们假设只传了一个模版文件的情况,那样的话render_to_string就会调用get_template方法获取指定的模版文件
# get_template 首先通过_engine_list获取到模版引擎
# _engine_list通过EngineHandler的实例化对象得到settings.TEMPLATES的所有模版引擎相关的信息
# EngineHandler在程序启动时就将模版引擎缓存起来了,不过这里还是先说下它的过程,由于对象本身实现了iter方法,所有我们对数据进行迭代时,会触发该方法
# 然后找到对象的templates属性,该属性通过获取settings.TEMPLATES这个列表形式的模版引擎信息,可以有多个模版引擎,每一个引擎都是字典形式存在,且必须
#包含那些KEY,并保存一个副本,将每个引擎的`BACKEND`KEY值以点形式从右开始分割2次,取倒数第二个元素为引擎的名称,这样默认的引擎,名称就是django。
# 然后设置引擎的NAME、DIRS、APP_DIRS、OPTIONS的值,最终所有的模版引擎以字典形式返回,KEY为引擎的名称
# _engine_list调用EngineHandler对象的all方法,all方法通过列表推导遍历self对象本身,也就是在调用__iter__方法,并使用self[alias]这种语法糖形式,
# 实际调用的就是self本身实现的__getitem__方法,将值取出来,每个alias就是上面所分析的所有以KEY方法存到字典的模版引擎,通过__getitem__传入该KEY,再调用
# self.templates[alias]方式,self.templates本身返回的是一个有序字典,所有可以这么取字典的值。通过这样就可以得到每个模版引擎的信息。__getitem__每
# 获取到一个引擎信息时,都将BACKEND对应的值的字符串形式的的模块名通过import_string方法导入该具体的模块,并将得到的模块返回,这里的默认引擎为
# django.template.backends.django.DjangoTemplates,import_string导入时会先导入模块,再获取模块的属性DjangoTemplates,然后返回该属性。
# 接着__getitem__通过得到的DjangoTemplates,进行实例化,并把这个引擎相关的信息参数形式传入。
# _engine_list得到的就是一个包含所有模版引擎的对象,这里实际上就是DjangoTemplates对象,
# get_template在遍历_engine_list返回的每一个引擎,然后调用引擎的get_template方法,并把模版名称传入。
# DjangoTemplates实例化时,会将所有APP下的templatetags模块下的tag加载。每个tag必须包含`register`这个属性,也就是你定义tag装饰器时,取的名称必须
# 是register = Library(),名字不能随意,否则不会加载这种tag,
# 这些tag都赋值给libraries每个模版的引擎的option的key值。通过settings也可以手动指定其它位置的tag模块,
# 还将这些参数传递给Engine进行实例化,还记得平时我们的模版不引用tag也有一些默认tag可用么,其实就是这时导入了一些默认的tag,并赋值给对象的template_builtins。
# 默认的default_builtins = [
# 'django.template.defaulttags',
# 'django.template.defaultfilters',
# 'django.template.loader_tags',
# ]
def render(request, template_name, context=None, content_type=None, status=None, using=None):
content = render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)
def render_to_string(template_name, context=None, request=None, using=None):
"""
Loads a template and renders it with a context. Returns a string.
template_name may be a string or a list of strings.
"""
if isinstance(template_name, (list, tuple)):
template = select_template(template_name, using=using)
else:
template = get_template(template_name, using=using)
return template.render(context, request)
def get_template(template_name, using=None):
"""
Loads and returns a template for the given name.
Raises TemplateDoesNotExist if no such template exists.
"""
chain = []
engines = _engine_list(using)
for engine in engines:
try:
return engine.get_template(template_name)
except TemplateDoesNotExist as e:
chain.append(e)
raise TemplateDoesNotExist(template_name, chain=chain)
def _engine_list(using=None):
return engines.all() if using is None else [engines[using]]
class EngineHandler(object):
def __init__(self, templates=None):
"""
templates is an optional list of template engine definitions
(structured like settings.TEMPLATES).
"""
self._templates = templates
self._engines = {}
@cached_property
def templates(self):
if self._templates is None:
self._templates = settings.TEMPLATES
templates = OrderedDict()
backend_names = []
for tpl in self._templates:
tpl = tpl.copy()
try:
# This will raise an exception if 'BACKEND' doesn't exist or
# isn't a string containing at least one dot.
default_name = tpl['BACKEND'].rsplit('.', 2)[-2]
except Exception:
invalid_backend = tpl.get('BACKEND', '<not defined>')
raise ImproperlyConfigured(
"Invalid BACKEND for a template engine: {}. Check "
"your TEMPLATES setting.".format(invalid_backend))
tpl.setdefault('NAME', default_name)
tpl.setdefault('DIRS', [])
tpl.setdefault('APP_DIRS', False)
tpl.setdefault('OPTIONS', {})
templates[tpl['NAME']] = tpl
backend_names.append(tpl['NAME'])
counts = Counter(backend_names)
duplicates = [alias for alias, count in counts.most_common() if count > 1]
if duplicates:
raise ImproperlyConfigured(
"Template engine aliases aren't unique, duplicates: {}. "
"Set a unique NAME for each engine in settings.TEMPLATES."
.format(", ".join(duplicates)))
return templates
def __getitem__(self, alias):
try:
return self._engines[alias]
except KeyError:
try:
params = self.templates[alias]
except KeyError:
raise InvalidTemplateEngineError(
"Could not find config for '{}' "
"in settings.TEMPLATES".format(alias))
# If importing or initializing the backend raises an exception,
# self._engines[alias] isn't set and this code may get executed
# again, so we must preserve the original params. See #24265.
params = params.copy()
backend = params.pop('BACKEND')
engine_cls = import_string(backend)
engine = engine_cls(params)
self._engines[alias] = engine
return engine
def __iter__(self):
return iter(self.templates)
def all(self):
return [self[alias] for alias in self]
engines = EngineHandler()
class DjangoTemplates(BaseEngine):
app_dirname = 'templates'
def __init__(self, params):
params = params.copy()
options = params.pop('OPTIONS').copy()
options.setdefault('autoescape', True)
options.setdefault('debug', settings.DEBUG)
options.setdefault('file_charset', settings.FILE_CHARSET)
libraries = options.get('libraries', {})
options['libraries'] = self.get_templatetag_libraries(libraries)
super(DjangoTemplates, self).__init__(params)
self.engine = Engine(self.dirs, self.app_dirs, **options)
def from_string(self, template_code):
return Template(self.engine.from_string(template_code), self)
def get_template(self, template_name):
try:
return Template(self.engine.get_template(template_name), self)
except TemplateDoesNotExist as exc:
reraise(exc, self)
def get_templatetag_libraries(self, custom_libraries):
"""
Return a collation of template tag libraries from installed
applications and the supplied custom_libraries argument.
"""
libraries = get_installed_libraries()
libraries.update(custom_libraries)
return libraries
django的templatetags的更多相关文章
- 2 django系列之django分页与templatetags
preface 当页面出现的条目多的时候,我们就需要使用分页功能了.Django作为一个知名的web框架,自然也提供了分页功能,下面说说它. Python-shell 练练手 在python下入手 先 ...
- django分页功能,templatetags的应用
django 将不会将得到的html代码自动转化 from django.utils.html import format_html html =''' <a href='http://www. ...
- Django 自定义标签与过滤器报错 No module named 'templatetags'
Django 自定义标签与过滤器报错 按照网上的教程如果想使用自定义的标签与过滤器就得往settings.py中添加下列数据 TEMPLATES = [ { 'BACKEND': 'django.te ...
- Django 自定义模板标签TemplateTags
创建自定义的模板标签(template tags) Django提供了以下帮助函数(functions)来允许你以一种简单的方式创建自己的模板标签(template tags): simple_tag ...
- 《Django By Example》第三章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:第三章滚烫出炉,大家请不要吐槽文中 ...
- Django
一.Django 简介 Django 是一个由 Python 写成的开放源代码的 Web 应用框架.它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是 CMS(内容管理系统) ...
- python框架之django
python框架之django 本节内容 web框架 mvc和mtv模式 django流程和命令 django URL django views django temple django models ...
- Django基础之安装配置
安装配置 一 MVC和MTV模式 著名的MVC模式:所谓MVC就是把web应用分为模型(M),控制器(C),视图(V)三层:他们之间以一种插件似的,松耦合的方式连接在一起. 模型负责业务对象与数据库的 ...
- Python 【第十一章】 Django模版
1.直接传值 urls.py """mysite URL Configuration The `urlpatterns` list routes URLs to view ...
随机推荐
- C# 5.0 CallerMemberName CallerFilePath CallerLineNumber获取调用方法名称,路径,行号
class Program { static void Main(string[] args) { Log("测试"); Console.Read(); } public stat ...
- 51Nod1868 彩色树 虚树
原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1868.html 题目传送门 - 51Nod1868 题意 给定一颗 $n$个点的树,每个点一个 $[ ...
- HDU2586How far away? LCA
去博客园看该题解 题意 给出一棵树,以及每条边的权值,给出一些询问,每个询问是2个节点,求每个询问对应的2个节点的距离. 算法 LCA_Tarjan 代码 #include <cstring&g ...
- 005 使用SpringMVC开发restful API三--处理创建请求
一:主要任务 1.说明 @RequestBody 映射请求体到java方法的参数 日期类型参数的处理 @Valid注解 BindingResult验证请求参数的合法性并处理校验结果 二:@Reques ...
- LoadRunner的函数
一.基础函数 在VU左边导航栏中,有三个LR框架函数,分别是vuser_init(),Action(),vuser_end(). 这三个函数存在于任何Vuser类型的脚本中: ●vuser_init ...
- day5 列表的增删改查
1,列表的增删改查,其他操作.2,元祖.3,列表的嵌套操作.4,开一点dict. 昨日内容回顾: 字符串的方法:1,find通过元素找索引,可切片,找不到返回-12,index,找不到报错.3,spl ...
- HDU 1385 Minimum Transport Cost (输出字典序最小路径)【最短路】
<题目链接> 题目大意:给你一张图,有n个点,每个点都有需要缴的税,两个直接相连点之间的道路也有需要花费的费用.现在进行多次询问,给定起点和终点,输出给定起点和终点之间最少花费是多少,并且 ...
- 使用ORM进行前后端数据交互
使用ORM进行数据交互 前期准备 必备知识:ORM操作,数据库多表操作.Django部分知识. 三张表:班级.老师.学生 一对多关系:班级与学生 多对多关系:班级与老师 #创建班级表 class Cl ...
- python实现链表(一)
单链表结构简单,组成为节点 节点实现方法我们采用类进行封装 def __init__(self,item): self.item=item self.next=None 在这里我们实现对链表的操作时可 ...
- shell script exit if any command fails
dd this to the beginning of the script: set -e This will cause the shell to exit immediately if a si ...