Django学习笔记----3.模板

模板

​ DTL为Django 内置的模板语言,可以实现和Django的无缝衔接。

  • 渲染模板

    1. render_to_string

      找到模板,然后把模板编译后渲染成Python的字符串格式,最后再通过HttpResponse 类包装成一个HttpResponse对象返回回去。

      from django.template.loader import render_to_string
      from django.http import HttpResponse
      def book_detail(request,id):
          html = render_to_string("index.html")
          return HttpResponse(html)
      
    2. django给提供了一个更为简便的方式,直接将模板渲染成字符串和包装成HttpResponse对象。

      from django.shortcuts import render
      def book_list(request):
      	return render(request,'list.html')
      
  • 模板查找路径配置

    在setting.py文件中,有一个TEMPLATES配置,这个配置包含了模板引擎的配置。

    1. DIRS

      这是一个列表,在这个列表中可以存放所有的模板路径,以后在视图中使用render或者render_to_string 渲染模板时,会在这个列表中查找模板。

    2. APP_DIRS

      默认true,会在INSTEALLED_APPS的安装了的APP下的templates文件中查找模板。

    3. 查找顺序

      先在DIRS这个列表中依次查找路径下有没有模板;如果没有,再检查当前视图所处的app是否已经安装了,如果已经安装了,那么就在当前app下的templates文件夹中查找模板;如果没有再去其他已经安装的app中查找。如果没有抛出异常,TemplateDoesNotExist。

  • DTL模板语法

    • 变量

      模板中可以包含变量。在视图中通过render或render_to_string的context参数,为一个字典类型。

      # index.html 模板
      <p>{
               {
                username }}</p>
      # views.py 视图
      def index(requets):
          return render(request,'index.html',context={
               'username':'zzz'}
      

      模板中的变量也支持(.) 比如 person.username

      1. 如果person是一个字典,那么就会查找这个字典的username这个的key值
      2. 如果person是一个对象,那么就会查找这个对象的username属性,或者username这个方法。
      3. 如果出现person.1,会判断person是否是一个列表或者元组或者任意的可以通过下标访问的对象。如果是的话就取这个列表的第1个值;如果不是就获取到的是一个空的字符串。
    • 模板标签

      1. if 标签

        if 标签相当于 Python 中的 if 语句,有 elif 和 else 相对应,但是所有的标签都需要用标签符号( {%%} )进行包裹。 if 标签中可以使用 ==、!=、<、<=、>、>=、in、not in、is、is not 等判断运算符

      2. for…in … 标签

        for…in… 标签: for…in… 类似于 Python 中的 for…in… 。可以遍历列表、元组、字符串、字典等一切可以遍历的对象。

        如果想要反向遍历,那么在遍历的时候就加上一个 reversed 。

      3. for…in…empty 标签

        这个标签使用跟 for…in… 是一样的,只不过是在遍历的对象如果没有元素的情况下,会执行 empty 中的内容。

        {
                   % for person in persons %}
        <li>{
                   {
                    person }}</li>
        {
                   % empty %}
        暂时还没有任何人
        {
                   % endfor %}
        
      4. with 标签

        在模版中定义变量。有时候一个变量访问的时候比较复杂,那么可以先把这个复杂的变量缓存到一个变量上,以后就可以直接使用这个变量就可以了。

        context = {
                   
        "persons": ["张三","李四"]
        }
        {
                   % with lisi=persons.1 %}
        <p>{
                   {
                    lisi }}</p>
        {
                   % endwith %}
        
        {
                   % with persons.1 as lisi %}
        <p>{
                   {
                    lisi }}</p>
        {
                   % endwith %}
        

        注意with中定义的变量 只能在with中使用;定义变量时,等号两天不能留有空格。

      5. url 标签

        在模板中,可以使用反转的方式来实现url。

        # path部分
        path('detail//',views.book_detail,name='detail')
        <a href="{% url 'book:detail' %}">图书列表页面</a>
        # url反转,使用位置参数
        <a href="{% url 'book:detail' 1 %}">图书详情页面</a>
        # url反转,使用关键字参数
        <a href="{% url 'book:detail' book_id=1 %}">图书详情页面</a>
        # 要传递查询字符串的参数
        <a href="{% url 'book:detail' book_id=1 page=2 %}">图书详情页面</a>
        
      6. spaceless 标签

        移除html标签中的空白字符

        {
                   % spaceless %}
        <p>
        <a href="foo/">Foo</a>
        </p>
        {
                   % endspaceless %}
        
      7. autoescape 标签

        开启和关闭这个标签内元素的自动转义功能。

        # 传递的上下文信息
        context = {
                   
        "info":"百度"
        }
        # 模板中关闭自动转义
        {
                   % autoescape off %}
        {
                   {
                    info }}
        {
                   % endautoescape %}
        
      8. verbatim 标签

        默认在DTL模板中会解析那些特殊字符。如果不想使用DTL的解析引擎,可以把代码放在verbatim中。

    • 模板常用过滤器

      1. add

        将传进来的参数添加到原来的值上面。如果可以转换成整形,那就相加;如果不能就进行拼接。{ { value|add:"2" }} 如果value为4,则结果为6。

        # add过滤器源码
        def add(value, arg):
        	"""Add the arg to the value."""
        	try:
        		return int(value) + int(arg)
        	except (ValueError, TypeError):
        		try:
        			return value + arg
        		except Exception:
        			return ''
        
      2. cut

        移除值中所有指定的字符串。类似于python中的replace(args,"")。{ { value|cut:" " }}

        def cut(value, arg):
        	"""Remove all values of arg from the given string."""
        	safe = isinstance(value, SafeData)
        	value = value.replace(arg, '')
        	if safe and arg != ';':
        		return mark_safe(value)
        	return value
        
      3. date

        将一个日期按照指定的格式,格式化成字符串。

        # 数据
        context = {
                   
        "birthday": datetime.now()
        }
        # 模版
        {
                   {
                    birthday|date:"Y/m/d" }} # 输出 0000/00/00
        Y 四位数字的年份 2018
        m 两位数字的月份 01-12
        n 月份,1-9前面没有0前缀 1-12
        d 两位数字的天 01-31
        j 天,但是1-9前面没有0前缀 1-31
        g 小时,12小时格式的,1-9前面没有0前缀 1-12
        h 小时,12小时格式的,1-9前面有0前缀 01-12
        G 小时,24小时格式的,1-9前面没有0前缀 1-23
        H 小时,24小时格式的,1-9前面有0前缀 01-23
        i 分钟,1-9前面有0前缀 00-59
        s 秒,1-9前面有0前缀 00-59
        
      4. default

        如果值被评估为False,都会使用default过滤器提供的默认值。{ { value|default:"nothing" }} 如果 value 是等于一个空的字符串。比如 “” ,那么以上代码将会输出 nothing 。

      5. default_if_none

        如果值是 None ,那么将会使用 default_if_none 提供的默认值。

      6. first

        返回列表/元组/字符串中的第一个元素。{ { value|first }}

      7. last

        返回列表/元组/字符串中的最后一个元素。

      8. floatformat

        使用四舍五入的方式格式化一个浮点类型。

      9. join

        将列表/元组/字符串。{ { value|join:"/" }}

      10. length

        获得一个列表/元组/字符串/字典的长度。{ { value|length }}

      11. lower

        将值中所有的字符全部转换成小写。{ { value|lower }}

      12. upper

        是将指定的字符串全部转换成大写。

      13. random

        在被给的列表/字符串/元组中随机的选择一个值。{ { value|random }}

      14. safe

        标记一个字符串是安全的。也即会关掉这个字符串的自动转义。

      15. slice

        类似于 Python 中的切片操作。{ { some_list|slice:"2:" }}

      16. stringtags

        删除字符串中所有的 html 标签。

      17. truncatechars

        如果给定的字符串长度超过了过滤器指定的长度。那么就会进行切割,并且会拼接三个点来作为省略号。

      18. truncatechars_html

        不会切割 html 标签 { { value|truncatechars:5 }}

    • 自定义模板过滤器

      模版过滤器必须要放在 app 中,并且这个 app 必须要在 INSTALLED_APPS 中进行安装。然后再在 这个 app 下面创建一个 Python包 叫做 templatetags 。再在这个包下面创建一个 python文件 。

      过滤器实际上就是python中 的一个函数,只不过是把这个函数注册到模板库中,以后在模板中就可以使用这个函数了。但是这 个函数的参数有限制,第一个参数必须是这个过滤器需要处理的值,第二个参数可有可无,如果 有,那么就意味着在模板中可以传递参数。并且过滤器的函数最多只能有两个参数。在写完过滤 器后,再使用 django.template.Library 对象注册进去。

      from django import template
      
      # 创建模板库对象
      register = template.Library()
      #过滤器函数  value 需要处理的值 mystr 可以传递的参数
      def mycut(value,mystr):
          return value.replace(mystr)
      #将函数注册到模板库中
      register.filter("mycut",mycut)
      

      以后想要在模板中使用这个过滤器,就要在模板中load一下这个过滤器所在的模块的名字。

      {
               % load my_filter %}
      
      # 自定义时间计算过滤器
      # time_filter.py 文件
      from datetime import datetime
      from django import template
      
      register = template.Library()
      
      def time_since(value):
          """
          time距离现在的时间间隔
          1.如果时间间隔小于1分钟,那么就显示"刚刚"
          2.如果是大于1分钟小于1小时,那么就显示“xx分钟前”
          3.如果是大于1小时小于24小时,那么就显示“xx小时前”
          4.如果是大于24小时小于30天以内,那么就显示“xx天前”
          5.否则就是显示具体的时间 2017/10/20 16:15	
          """
          if isinstance(value,datetime):
              now = datetime.now()
              timestamp = (now - value).total_seconds()
              if timestamp < 60:
                  return "刚刚"
              elif timestamp >= 60 and timestamp < 60*60:
                  minutes = int(timestamp/60)
                  return "%s分钟前" % minutes
              elif timestamp >= 60*60 and timestamp <60*60*24:
                  hours = int(timestamp/(60*60))
                  return "%s小时前" % hours
              elif timestamp >= 60*60*24 and timestamp < 60*60*24*30:
                  day = int(imestamp / (60*60*24))
                  return "%s天前" % days
              else:
                  return value.strftime("%Y/%m/%d %H:%M")
          else:
              return value
         
      register.filter("time_since",time_since)
      

      在模板中使用的示例

      {
               % load time_filter %}
      ...
      {
               % value|time_since %}
      ...
      

      为了更加方便的将函数注册到模板库中,当作过滤器,也可以使用装饰器来将一个函数包装成过滤器。

      from django import template
      register = template,Library()
      
      @register.filter(name='mycut')
      def mycut(value,mystr):
          return value.replace(mystr,"")
      
    • 模块结构优化

      • 引用模块

        有时候一些代码是在许多模板中都用到的。如果我们每次都重复去拷贝代码,那肯定不符合项目的规范。一般我们可以把这些重复性的代码抽取出来,以后想要使用这些代码的时候,通过include包含进来。

        # header.html
        <p>heaer</p>
        
        # footer.html
        <p>footer</p>
        
        #main.html
        {
                   % include 'header.html' %}
        <p>main</p>
        {
                   % include 'footer.html' %}
        

        可以用过with语句来传递参数

        # header.html
        <p>用户名 {
                   {
                    username }}</p>
        # main.html
        {
                   % include "header.html" with username='huangyong' %}
        
      • 模板继承

        模版继承也可以在父模版中先定义好一些 子模版需要用到的代码,然后子模版直接继承就可以了。并且因为子模版肯定有自己的不同代码, 因此可以在父模版中定义一个block接口,然后子模版再去实现。

        # base.html
        {
                   % load static %}
        <!DOCTYPE html>
        <html lang="en">
        <head>
        	<link rel="stylesheet" href="{% static 'style.css' %}" />
        	<title>{
                   % block title %}我的站点{
                   % endblock %}</title>
        </head>
        <body>
        	<div id="sidebar">
        		{
                   % block sidebar %}
        		<ul>
        			<li><a href="/">首页</a></li>
        			<li><a href="/blog/">博客</a></li>
        		</ul>
        		{
                   % endblock %}
        	</div>
        	<div id="content">
        		{
                   % block content %}{
                   % endblock %}
        	</div>
        </body>
        </html>
        
        # 子模板 通过extends标签来实现
        {
                   % extends "base.html" %} # 注意必须放在模板的第一行
        
        {
                   % block title %}博客列表{
                   % endblock %} # 子模板必须放在block中
        
        {
                   % block content %}
        	{
                   % for entry in blog_entries %}
        		<h2>{
                   {
                    entry.title }}</h2>
        		<p>{
                   {
                    entry.body }}</p>
        	{
                   % endfor %}
        {
                   % endblock %} # ,还可以在 block 结束的时候也定义上名字}{% endblock content %} 
        
    • 加载静态文件

      使用static标签来加载静态文件。

      1. 首先确保django.contrib.staticfiles 已经添加到setting.INSTALLED_APPS中

      2. 确保在settings.py中设置了STATIC_URL。

      3. 在已经安装了的app下创建一个文件夹叫做static,然后在这个static文件夹中创建一个当前app的名字的文件夹,再把静态文件放在这个文件夹下。比如 book/static/book/logo.jpg

      4. 如果存在一些静态文件和任何app无关的,那么可以再setting.py中添加STATICFILES_DIRS ,然后在根目录下创建static

        STATICFILES_DIRS = [
            os.path.join(BASE_DIR,"static")
        ]
        
      5. 在模板中使用load标签加载static标签。

        {
                   % load static %}
        <link rel="stylesheet" href="{% static 'style.css' %}">
        
      6. 如果不想每次在模版中加载静态文件都使用 load 加载 static 标签,那么可以 在 settings.py 中的 TEMPLATES/OPTIONS 添加 ‘builtins’: [‘django.templatetags.static’] ,这样以后在模版中就可以直接使用 static 标签,而不用 手动的 load 了。

你可能感兴趣的:(django,python,django,后端,前端)