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 ...
随机推荐
- codeforces div2 C题思路训练【C题好难,我好菜】
1017C The Phone Number: 构造数列使得LIS和LDS的和最小,定理已知LIS=L,LDS=n/L的向上取整,根据样例可以得到设置L=根号n,构造方法如样例 截断法构造,不用考虑边 ...
- A - Points and Segments CodeForces - 429E
题解: 方法非常巧妙的一道题 首先考虑要求全部为0怎么做 发现是个欧拉回路的问题(很巧妙) 直接dfs一遍就可以了 而这道题 要求是-1,1,0 我们可以先离散化 完了之后判断每个点被奇数还是偶数条边 ...
- 构建简单的json树形菜单
json结构: var Menu = [{ tit:"一级菜单", submenu:[{ tit:"二级菜单", url:"", func: ...
- ionic2程序调试
新手一枚,之前一直做.net开发,最近接触Ionic2,也没有人带,只能自己一点点抠文档,查资料.一直苦于无法直接调试打包发不好的app,只能在代码里面加上alert一点一点的抛出要看信息,感觉就像瞎 ...
- Kudu的集群安装(1.6.0-cdh5.14.0)
kudu的架构体系 下图显示了一个具有三个 master 和多个 tablet server 的 Kudu 集群,每个服务器都支持多个 tablet.它说明了如何使用 Raft 共识来允许 maste ...
- ncat
ncat 或者说 nc 是一款功能类似 cat 的工具,但是是用于网络的.它是一款拥有多种功能的 CLI 工具,可以用来在网络上读.写以及重定向数据. 它被设计成可以被脚本或其他程序调用的可靠的后端工 ...
- dns-prefetch,新打开页面预抓取
dns-prefetch 对性能提升有多大 转载2016-04-07 12:57:41 标签:网站推广dns-prefetch对性能提 dns-prefetch, 是DNS预获取,也是网页前端的优化的 ...
- HDU5692 Snacks DFS序 线段树
去博客园看该题解 题目 HDU5692 Snacks Problem Description 百度科技园内有n个零食机,零食机之间通过n−1条路相互连通.每个零食机都有一个值v,表示为小度熊提供零食的 ...
- 05. Matplotlib 1 |图表基本元素| 样式参数| 刻度 注释| 子图
1.Matplotlib简介及图表窗口 Matplotlib → 一个python版的matlab绘图接口,以2D为主,支持python.numpy.pandas基本数据结构,运营高效且有较丰富的图表 ...
- Scala-Unit7-Scala并发编程模型AKKA
一.Akka简介 Akka时spark的底层通信框架,Hadoop的底层通信框架时rpc. 并发的程序编写很难,但是Akka解决了spark的这个问题. Akka构建在JVM平台上,是一种高并发.分布 ...