标签:封装 循环 static xtend 问题 cts and 过滤器 ast
目录
模板按照我的理解,就是让html中内容不固定,让html内容已后端的方式动态起来(虽然前端mvvm框架也也开始有模板概念,所以广义说模板概念不限于后端)。但是html基础的内容还是是固定的。模板通过类编程的模板语法,可以将html模板中的动态内容,通过后端程序的计算传入核心数据,最后通过模板语法得到一个完整的html。模板的构造核心就是:模板语法和上下文数据(渲染引擎的全局数据和后端代码传入的数据);模板的驱动就是模板引擎(如Jinja2,django内置的DTL)。模板语法的数据来自于上下文数据,使得模板可以动态的生成html内容,关键让类似内容的构造更加高效,如for循环渲染列表。模板语法还提供模板与模板间存在关系:继承关系和包含关系。模板间的关系时的开发网页减少大量的冗余内容。
后端使用模板,多用于开发访问量较小的后台管理系统。
模版文件中使用的variables会被上下文字典中的对应的key的值所替代。
模版文件中使用的tags会被引擎执行一段相应的逻辑。
内置filter: 参见官档索引
内置tag:参见官档索引
{% load static %} 加载static app中templatetags目录下的static文件中定义的tag。
load同时也会导入tag和filter
Tags的功能比filter要复杂的多,因为tag几乎可以做任何事情,包括最重要的渲染模版inclusion_tag。而filter主要是对数据进行处理。
# my_tags.py
from django import template
register = template.Library() # register变量名固定
@register.filter # 自定义filter
def multi_tag(v1, v2):
return v1 * v2
@register.simple_tag # 自定义simple tag
def tag_add(v1, v2):
return v1 + v2
如果变量指向的也是一个字典:那么使用dotted可以访问了字典中的值:{{ my_dict.key }} {{ my_object.attribute }} {{ my_list.0 }}
request对象自动传入
render(‘inde.html‘, {已字典结构传入})
通过{% extends ‘父模板.hmtl‘ %}‘
通过{% include ‘插入的模板.html‘ %} , 说明插入的模板可以使用数据
inclusion_tag 通过自定义tag形式,tag绑定了一个模板,tag函数处理逻辑放回一个上下文字典供绑定的模板渲染。这种也相当于是模板的包含关系,只不过是通过一个自定义的inclusion_tag进行封装。且让插座与插头对接更为明确,就是提供给tag提供参数,参数就是对接的规范了。由于是tag的形式,tag函数代码可以访问后台的所有数据。
? ?? ?下面代码将一个模版通过使用自定义的类型为inclusion tag即进行渲染使用:
? ?? ?这个自定义tag是怎么做到的呢?
? ?? ?首先,我们利用这个tag的场景是:多个url页面都要用到相同的页面布局内容。如:博客系统中的个人站点的用户文章列表,标签列表,公告;这些对于这个用户的站点内容都是一样的。这些共同的东西要怎么才能重复利用呢?对于学习了template继承知识的同学,可能想到的是使用继承关系既可以了。继承是没错,但是相同部分的内容,要提供给模版语言的数据还是要给予的,不同的是这些数据在各自的视图view函数中,要去重复的获取数据,这些重复的获取数据的代码,在这些视图之间都是一样的。虽然模版得到了继承,但是模版要用到的数据还是造成了重复代码。要解决这个问题方式一:可以将获取数据的代码,封装到一个函数代码块中,这样能解决重复问题。这是利用基于模版的继承为主要思想的思路,因为模版必须继承才行。
? ?? ?上面提到的模版继承思路,有一个局限性就是耦合度太高,必须继承模版。有没有什么方法不用继承模版就可以实现相同页面块的即插即用(继承方式无法即插即用)。django的一个自定义tag类型,给我们提供了一种即插即用的思路,这种思路是基于模版语言的tag对应一个python函数逻辑的思想。只需要自定义一个tag,tag就可以在任何的模版中插入使用。tag要做的就是返回一个渲染了的在前面提到的重复页面就行了。(这个就类似与include内置tag功能的一样,不同的是,include的页面是死的页面;而这里自定义的tag是可以利用模版语言结合上下文数据,动态的渲染出这个即插即用的页面)。这个指定tag就是django的inclusion tags。
inlucsion tags 的使用需要准备两个东西:一个即插即用的template,另一个就是渲染模版的上下文context data数据了。这个数据就是我们第一种思想中提到的要通过一个封装函数获取的数据。其实参数就是通过被插入的主模版能够给我们提供的数据了。即插即用,解耦的思想很棒!下面过一个列子来实践这个即插即用的思想。
友情提醒一句:利用这个思想,首先是目的和使用场景,前端页面要重复使用有且并且要重复的页面的上下文数据获取较多比较麻烦且重复
开始示例:
{# 公告 #}
<div class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title">公告</h3>
</div>
<div class="panel-body">
<ul class="panel-list" type="none">
<li><span>用户别名: {{ user_obj.username }}</span></li>
<li><span>园龄: {{ age_days }} 天</span></li>
<li><span>随笔数: {{ user_obj.article_set.count }} 篇</span></li>
</ul>
</div>
</div>
{#随笔分类#}
<div class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title">随笔分类</h3>
</div>
<div class="list-group">
{% for item in article_category_queryset %}
<a href="" class="list-group-item">{{ item.category__title }} ({{ item.count }})</a>
{% endfor %}
</div>
</div>
{#标签#}
<div class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title">我的标签</h3>
</div>
<div class="list-group">
{% for item in article_tag_queryset %}
<a href="" class="list-group-item">{{ item.title }} ({{ item.count }})</a>
{% endfor %}
</div>
</div>
{#归档#}
<div class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title">随笔归档</h3>
</div>
<div class="list-group">
{% for item in article_archive_queryset %}
<a href="" class="list-group-item">{{ item.y_m }} ({{ item.count }})</a>
{% endfor %}
</div>
</div>
重复获取的上下问数据就在该文件中函数中实现,返回一个上下文数据字典。在利用渲染装饰器来装饰这个函数,装饰器函数要带入要渲染的模版文件。相当于就是装饰器给我们做渲染模版作用,我们的自定义函数来获取查询数据,返回渲染需要的上下文数据就行。
from django import template
from myblog import models
from django.utils import timezone
from django.db.models import Count
register = template.Library()
@register.inclusion_tag('myblog/stuff_list.html') # 绑定我们的模板了
def stuff_list(user_obj): # 参数需要一个,这里就是用户对象
# 计算园龄 以天为单位
curr_time = timezone.now()
create_time = user_obj.create_time
interval_timedelta = curr_time - create_time
age_days = interval_timedelta.days
user_articles = models.Article.objects.filter(user=user_obj)
# 分类
article_category_queryset = user_articles.values('category__pk').annotate(
count=Count('pk')).values('category__title', 'count')
# 标签
# article_tag_queryset = user_articles.values('tag__pk').annotate(count=Count('pk')).values('tag__title', 'count') 这个计算出来是一个{'None': 6} 把None做了一个分类,下面分组方式就是一个[]的queryset。两种看来还是不一样。
article_tag_queryset = models.Tag.objects.filter(blog=user_obj.blog).values('pk').annotate(
count=Count('article__pk')).values('title', 'count')
print(article_tag_queryset) ###
article_archive_queryset = user_articles.extra(select={'y_m': "date_format(create_time, '%%Y-%%m')"}).values(
'y_m').annotate(count=Count('pk')).values('y_m', 'count')
print(article_archive_queryset) ###
# 这就是即插即用模版的上下文数据;通过一个user_obj参数我们就得到了要渲染到绑定模板中的上下文数据了。
return {'user_obj': user_obj,
'age_days': age_days,
'article_category_queryset': article_category_queryset,
'article_tag_queryset': article_tag_queryset,
'article_archive_queryset': article_archive_queryset,}
标签:封装 循环 static xtend 问题 cts and 过滤器 ast
原文地址:https://www.cnblogs.com/ZJiQi/p/10739600.html