• 创建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的更多相关文章

  1. 2 django系列之django分页与templatetags

    preface 当页面出现的条目多的时候,我们就需要使用分页功能了.Django作为一个知名的web框架,自然也提供了分页功能,下面说说它. Python-shell 练练手 在python下入手 先 ...

  2. django分页功能,templatetags的应用

    django 将不会将得到的html代码自动转化 from django.utils.html import format_html html =''' <a href='http://www. ...

  3. Django 自定义标签与过滤器报错 No module named 'templatetags'

    Django 自定义标签与过滤器报错 按照网上的教程如果想使用自定义的标签与过滤器就得往settings.py中添加下列数据 TEMPLATES = [ { 'BACKEND': 'django.te ...

  4. Django 自定义模板标签TemplateTags

    创建自定义的模板标签(template tags) Django提供了以下帮助函数(functions)来允许你以一种简单的方式创建自己的模板标签(template tags): simple_tag ...

  5. 《Django By Example》第三章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:第三章滚烫出炉,大家请不要吐槽文中 ...

  6. Django

    一.Django 简介 Django 是一个由 Python 写成的开放源代码的 Web 应用框架.它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是 CMS(内容管理系统) ...

  7. python框架之django

    python框架之django 本节内容 web框架 mvc和mtv模式 django流程和命令 django URL django views django temple django models ...

  8. Django基础之安装配置

    安装配置 一 MVC和MTV模式 著名的MVC模式:所谓MVC就是把web应用分为模型(M),控制器(C),视图(V)三层:他们之间以一种插件似的,松耦合的方式连接在一起. 模型负责业务对象与数据库的 ...

  9. Python 【第十一章】 Django模版

    1.直接传值 urls.py """mysite URL Configuration The `urlpatterns` list routes URLs to view ...

随机推荐

  1. RN错误随笔 - Unable to resolve module 'AccessibilityInfo'

    错误信息:.React Native 运行报错:Unable to resolve module 'AccessibilityInfo' 可以看到在 异常的返回的JSON 结构中给出了推荐的解决方法 ...

  2. C#搭建Oauth2.0认证流程以及代码示例

    我认为对于一个普遍问题,必有对应的一个简洁优美的解决方案.当然这也许只是我的一厢情愿,因为根据宇宙法则,所有事物总归趋于混沌,而OAuth协议就是混沌中的产物,不管是1...0a还是2.,单看版本号就 ...

  3. Python_函数_参数

    def   是函数的关键字,Python解释器一旦执行到def,默认不执行 def li(): n = 8 n +=1 print(n) li() li2 = li li2() 结果: 9 9 ret ...

  4. FastJson 支持配置的PropertyNamingStrategy四种策略

    摘要: FastJson默认使用CamelCase,在1.2.15版本之后,FastJson支持配置PropertyNamingStrategy,支持四种策略: CamelCase.PascalCas ...

  5. parted 分区命令

    fdisk  是针对 MBR的分区 ,因为MBR分区空间最大不能超过2T  最多分4个主分区 , 所以parted可以修改磁盘为GPT  可以支持更大的分区,更多的分区 1  查看分区 : #part ...

  6. Codeforces 1136E Nastya Hasn't Written a Legend 线段树

    vp的时候没码出来.. 我们用set去维护, 每一块区域, 每块区域内的元素与下一个元素的差值刚好为ki,每次加值的时候我们暴力合并, 可以发现我们最多合并O(n)次. 然后写个线段树就没了. #in ...

  7. appium---第三个脚本,进行模拟登陆

    我这边模拟的是第三方QQ登陆 刚开始顺风顺水,启动--我的--点击头像--跳转登陆--点击QQ登陆,以上都可以通过id寻找,因为都是同一个包名下,肯定有id,如果没有,一定是技术忘记了 ..... 然 ...

  8. svn创建分支(branch/tag)出现“path”already exists

    不用在visual svn中创建相应的目录,svn会自己创建目录,但是自己必须指定该目录名称. 比如:

  9. webpack的总结

    1,首先 项目的入口----package的入口 "scripts": { "dev": "node build/dev-server.js" ...

  10. selenium设置chrome和phantomjs的请求头信息

    selenium设置chrome和phantomjs的请求头信息   出于反爬虫也好-跳转到手机端页面也好都需要设置请求头,那么如何进行呢? 目录 一:selenium设置phantomjs请求头: ...