Django 模板

模板按照我的理解,就是让html中内容不固定,让html内容已后端的方式动态起来(虽然前端mvvm框架也也开始有模板概念,所以广义说模板概念不限于后端)。但是html基础的内容还是是固定的。模板通过类编程的模板语法,可以将html模板中的动态内容,通过后端程序的计算传入核心数据,最后通过模板语法得到一个完整的html。模板的构造核心就是:模板语法和上下文数据(渲染引擎的全局数据和后端代码传入的数据);模板的驱动就是模板引擎(如Jinja2,django内置的DTL)。模板语法的数据来自于上下文数据,使得模板可以动态的生成html内容,关键让类似内容的构造更加高效,如for循环渲染列表。模板语法还提供模板与模板间存在关系:继承关系和包含关系。模板间的关系时的开发网页减少大量的冗余内容。

后端使用模板,多用于开发访问量较小的后台管理系统。

模板语法

模版文件中使用的variables会被上下文字典中的对应的key的值所替代。

模版文件中使用的tags会被引擎执行一段相应的逻辑。

逻辑语法

  • {% if condition %} {% else %} 条件
  • {% for %} {% endfor%} 迭代

函数式过滤器

  • 说明: filter是用于转变 variable 和 tag's arguments 的
  • 例如: {{ django|title }} 其上下文 {'django': 'the web framework'}
  • 渲染后:'The Web Framework'
  • filter参数:有些filter是可以传入参数的,参数传入方式是filter:argument;
  • 例如: {{ datetime|date:"Y-m-d" }}

内置filter

内置filter: 参见官档索引

功能tag

  • 语法: {% tag %}
  • tag用法: 不同tag有自己的处理逻辑,包括用户自定义的tag,并且tag可以接受参数,有些tag有开始和结束tag对。
  • {% csrf_token %} 无参数
  • {% cycle 'odd' 'even' %} 有参数
  • {% if user.is_authenticated %} Hello, {{ user.username }}. {% endif %} 有开始和结束tag对的。
  • 说明:tag有内置,也可自定义。

注释

  • 语法:{# this won't be rendered #}
  • 作用:就是注释,不会被渲染。
  • 多行注释利用tag: {% comment %} 多行注释内容 {% endcomment %}
  • 说明: 为什么不用html的注释,因为模版语言不止用于html文本,其它文本也可以,所以在模版语言这一层来进行注释才行。注意,注释不能嵌套。

内置tag

内置tag:参见官档索引

导入三方tag and filter(load)

{% load static %} 加载static app中templatetags目录下的static文件中定义的tag。

load同时也会导入tag和filter

过滤器和功能tag的区别

Tags的功能比filter要复杂的多,因为tag几乎可以做任何事情,包括最重要的渲染模版inclusion_tag。而filter主要是对数据进行处理。

自定义tag和filter

  1. 前提:最常见是自定义的tag是在对应的app目录下的创建的,所以要将app注册到settings的installed_apps列表中。
  2. 在app目录下创建templatetags目录,名字必须固定,这个是默认查找加载指定自定义tag和filter文件的地方,并在目录创建__init__.py文件。(是django默认的finder查找逻辑限制了这个名字)
  3. 创建py文件,自定义tag就放在文件中。文件名一定要小心,不要和其它app注册的冲突了。自定义filter和tag,如:
# 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
  1. 自定义好自己的tags和filters,重要的一步就是将他们扩展使用到template引擎中,让他们生效就要使用{% load %} tag.
  2. 在模板文件中添加load标签后,需要重启服务。这点很关键啊!还有load后面的自定义tag保存的文件,不用引号,直接load后面跟文件名就行了
  3. 在模版中使用自定义tag和filter。模版间继承关系,是不会继承{% load %} 标签的,所以每个模版中要使用自定义的tag和filter都需要再次{% load %}一次。

上下文数据

  • 语法: {{ variable }}
  • 用法: My first name is {{ first_name }}. My last name is {{ last_name }}.
  • 非全局变量,需要提供的上下文字典(或者叫环境或者叫作用域):{'first_name': 'John', 'last_name': 'Doe'}
  • 通过render后产生的结果:My first name is John. My last name is 'Doe'.
  • 如果变量指向的也是一个字典:那么使用dotted可以访问了字典中的值:{{ my_dict.key }} {{ my_object.attribute }} {{ my_list.0 }}

全局数据

内置:官档

  • request对象自动传入

传入数据

  • render('inde.html', {已字典结构传入})

模板间关系

继承关系

通过{% extends '父模板.hmtl' %}'

包含关系

通过{% include '插入的模板.html' %} , 说明插入的模板可以使用数据

inclusion_tag关系

inclusion_tag 通过自定义tag形式,tag绑定了一个模板,tag函数处理逻辑放回一个上下文字典供绑定的模板渲染。这种也相当于是模板的包含关系,只不过是通过一个自定义的inclusion_tag进行封装。且让插座与插头对接更为明确,就是提供给tag提供参数,参数就是对接的规范了。由于是tag的形式,tag函数代码可以访问后台的所有数据。

inclusion_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数据了。这个数据就是我们第一种思想中提到的要通过一个封装函数获取的数据。其实参数就是通过被插入的主模版能够给我们提供的数据了。即插即用,解耦的思想很棒!下面过一个列子来实践这个即插即用的思想。

友情提醒一句:利用这个思想,首先是目的和使用场景,前端页面要重复使用有且并且要重复的页面的上下文数据获取较多比较麻烦且重复

开始示例:

  1. 模版stuff_list.html:

{# 公告 #}
<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>
  1. 自定义的tag文件my_tags_filters.py:

重复获取的上下问数据就在该文件中函数中实现,返回一个上下文数据字典。在利用渲染装饰器来装饰这个函数,装饰器函数要带入要渲染的模版文件。相当于就是装饰器给我们做渲染模版作用,我们的自定义函数来获取查询数据,返回渲染需要的上下文数据就行。

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,}
  1. 使用我们的inclusion_tag了,将my_tags_filters.py 放入到app目录下的templatetags目录下,然后再要使用的模板中进行{% load my_tags_filters %} 就可以了。然后使用tag {% stuff_list site_user %} 注意要传递我们的参数。

小结

  1. 从模板关系可以发散出:其实继承是非常好的内容重用减少冗余的设计,同时包含关系,也可以说是可插拔模式,插入即用,还可复用。包含关系多是用在画面构建方面,如设计图,html模板,画作等。
  2. 什么时候继承,什么时候包含:继承是框架,包含是插拔插件,包含是对继承的补充。继承局限更强,包含可跨继承。比如说,一个父模板,所有的子模版都是在继承父类的基础上修改覆盖。而包含可以在多个父模板中使用,突破了必须在一个父模板下的限制,但是包含不是随便插入,是类似插座和插头的概念,被插入模板需要提供给插入模板相关数据的。。
  3. 金字塔结构:通过模板引擎解析模板语法,根据传入上下文环境渲染出动态内容。模板语法。传入数据。

    tag和filter。模板关系。全局参数和传入参数。

    内置tag_filter和自定义tag_filter,tag功能强于filter。继承,include,inclusion_tag。request/auth。

Django学习之十三:提高页面开发效率减少冗余的模板系统的更多相关文章

  1. 提高 JavaScript 开发效率的高级 VSCode 扩展!

    原文:提高 JavaScript 开发效率的高级 VSCode 扩展! 作者:前端小智 Fundebug经授权转载,版权归原作者所有. Quokka.js Quokka.js 是一个用于 JavaSc ...

  2. 提高你开发效率的十五个Visual Studio 2010使用技巧

    提高你开发效率的十五个Visual Studio 2010使用技巧 相信做开发的没有不重视效率的.开发C#,VB的都知道,我们很依赖VS,或者说,我们很感谢VS.能够对一个IDE产生依赖,说明这个ID ...

  3. 极大提高Web开发效率的8个工具和建议(含教程)

    面对复杂的 Web 应用的开发,良好的流程和工具支持是必不可少的,它们可以让日常的开发工作更加顺畅.更加高效.本文介绍了6个Web开发利器以及相关的教程,帮助你在开发.调试.集成和发布过程极大地提高效 ...

  4. iOS开发——实用篇&提高iOS开发效率的方法和工具

    提高iOS开发效率的方法和工具 介绍 这篇文章主要是介绍一下我在iOS开发中使用到的一些可以提升开发效率的方法和工具. IDE 首先要说的肯定是IDE了,说到IDE,Xcode不能跑,当然你也可能同时 ...

  5. legend2---开发日志11(如何提高终极开发效率)

    legend2---开发日志11(如何提高终极开发效率) 一.总结 一句话总结: 实在没必要摸索着做,直接学了做,用专门的东西来做,岂不是要省时省事很多.岂不美哉. 1.vue中的滚动字幕动画效果如何 ...

  6. Django学习笔记(11)——开发图书管理页面

    一,项目题目: 开发图书管理页面 该项目主要练习Django对多个数据库进行增删改查的操作. 二,项目需求: 基础需求:75% 1. 列出图书列表.出版社列表.作者列表 2. 点击作者,会列出其出版的 ...

  7. Django学习笔记(9)—— 开发用户注册与登录系统

    一,项目题目: 开发用户注册与登录系统 该项目主要练习使用Django开发一个用户注册与登录的系统,通过这个项目然后巩固自己这段时间所学习的Django知识. 二,项目需求: 开发一个简单的用户登录与 ...

  8. 提高php开发效率的9大代码片段

    在网站开发中,我们都期望能高效快速的进行程序开发,如果有能直接使用的代码片段,提高开发效率,那将是极好的.php开发福利来了,今天小编就将为大家分享9大超实用的.可节省大量开发时间的php代码片段. ...

  9. itoo-快捷部署脚本--提高部署开发效率

     本次是第一次使用批处理文件来作为批量操作的工具,代替了人工的手动的复制,粘贴的方式,使用脚本实现了项目的启动.自动化部署,打开项目根目录.等等,提高了开发和调试的效率. 说明: 当前版本:1.0 ...

随机推荐

  1. ResultSet只返回一行数据的原因

    写之前,先告戒一下自己......写代码一定要细心,自己写的即使是非常简单的地方也要细心,不能自我感觉太良好,那往往可能会有些bug在等着你...... 注意事项: 1.当你为了查看数据库中是否存在某 ...

  2. Mysql访问权限问题:Access denied for user 'root'@'XXX' (using password: YES)

    System.Data.Entity.Core.ProviderIncompatibleException: An error occurred accessing the database. Thi ...

  3. Java开源生鲜电商平台-财务系统模块的设计与架构(源码可下载)

    Java开源生鲜电商平台-财务系统模块的设计与架构(源码可下载) 前言:任何一个平台也好,系统也好,挣钱养活团队这个是无可厚非的,那么对于一个生鲜B2B平台盈利模式( 查看:http://www.cn ...

  4. 【转】sentry 实时事件日志聚合平台

    1.install postgreSQL(v9.6)2.pip install sentry(v8.13.0)3.sentry init #初始化配置文件 4.配置好postgreSQL 需要连接re ...

  5. String的split()方法可以将字符串按照特定的分隔符拆分成字符串数组

    在java.lang包中有String.split()方法,返回是一个数组------不管按照什么拆,拆出来是一个数组 String str = "1,2,3,4,5,6"; St ...

  6. tomcat第一次使用正常启动后访问8080端口报404错误

    问题:tomcat第一次使用正常启动后访问8080端口报404错误 解决办法:双击tomcat调出tomcat的xml文件页面,Server Locations 默认是选第一行即Use Workspa ...

  7. Mysql服务启动与关闭

    启动: 在cmd中输入 net start mysql 关闭: 在cmd中输入  net stop mysql

  8. requests发送post请求的一些疑点

    前言 在Python爬虫中,使用requests发送请求,访问指定网站,是常见的做法.一般是发送GET请求或者POST请求,对于GET请求没有什么好说的,而发送POST请求,有很多朋友不是很清楚,主要 ...

  9. client,server,nginx 在使用keepAlive 专题

    2. TCP keepalive overview In order to understand what TCP keepalive (which we will just call keepali ...

  10. How to set spring boot active profiles with maven profiles

    In the previous post you could read about separate Spring Boot builds for a local development machin ...