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 ...
随机推荐
- Theorems for existence and uniqueness of variational problem
Introduction Among simulation engineers, it is well accepted that the solution of a PDE can be envis ...
- APM 原理与框架选型
发些存稿:) 0. APM简介 随着微服务架构的流行,一次请求往往需要涉及到多个服务,因此服务性能监控和排查就变得更复杂: 不同的服务可能由不同的团队开发.甚至可能使用不同的编程语言来实现 服务有可能 ...
- net core体系-web应用程序-2项目简单案例
阅读目录 NO1 留言板(mysql的使用) NO2 聊天室(WebSocket的使用) NO3 找工作(AngleSharp的使用) 部署多个站点 一些其它的细节 部署阿里云 mysql的客户端 ...
- Java中文字符所占的字节数
Java语言中,中文字符所占的字节数取决于字符的编码方式,一般情况下,采用ISO8859-1编码方式时,一个中文字符与一个英文字符一样只占1个字节:采用GB2312或GBK编码方式时,一个中文字符占2 ...
- 无法启动 Maya 集成的 qt designer 的解决方法和原因 以及 中英文切换
无法启动 Maya 集成的 qt designer 的解决方法和原因 以及 中英文切换 前言: Maya 集成了 PySide,同时集成了qt designer,在 Maya 的安装目录下的 bin ...
- 搭建本地maven库(nexus服务器)
第一步,下载https://www.sonatype.com/download-oss-sonatype 别下3.x版本,下2.x版本 第二步,解压,在bin目录下执行cmd命令,nexus inst ...
- Square Destroyer-POJ 1084 (IDA*)
Description The left figure below shows a complete 3*3 grid made with 2*(3*4) (=24) matchsticks. The ...
- POJ 2155 Matrix 【二维树状数组】(二维单点查询经典题)
<题目链接> 题目大意: 给出一个初始值全为0的矩阵,对其进行两个操作. 1.给出一个子矩阵的左上角和右上角坐标,这两个坐标所代表的矩阵内0变成1,1变成0. 2.查询某个坐标的点的值. ...
- Django分页(一)
Django分页(一) 手动实现简单分页 HTML <!DOCTYPE html> <html lang="en"> <head> <me ...
- Mybatis之占位符与拼接符
1.占位符 1.1 含义: 在持久化框架中,为了将约束条件中的可变参数从sql中分离出来,在原有的参数位置使用特殊的标记来标记该位置,后期通过代码给sql传递参数(即实现sql与代码分离开).这个特 ...