Django 模板层

Django settings源码

1.django其实有两个配置文件
一个是暴露给用户可以自定义的配置文件
项目根目录下的settings.py

一个是项目默认的配置文件
当用户不做任何配置的时候自动加载默认配置

# 默认全局配置文件,按住Ctrl键+鼠标左键点击可以进入查看
from django.conf import global_settings

2.配置文件变量名必须是大写
其实它的内部有个监测机制,一旦识别是小写,会通过逻辑判断自动排除掉
疑问:为什么当用户配置了就使用用户配置的 不配置就是要默认的

# 如果在django项目下其他文件需要用到配置文件,采用下面方式导入
# 既能拿到暴露给用户的配置,也能拿到全局的配置
from django.conf import settings

settings = LazySettings()

# manage.py
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")

ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
class LazySettings(LazyObject):
    def _setup(self, name=None):
        # os.environ看成是一个全局大字典      'app.settings'
        settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
        self._wrapped = Settings(settings_module)  # Settings('day05.settings')
 
class Settings(object):
    def __init__(self, settings_module):  # 'app.settings'
        for setting in dir(global_settings):  # 获取全局配置文件里面所有的变量名
            if setting.isupper():  # 校验是否是纯大写
                setattr(self, setting, getattr(global_settings, setting))
                # 给Settings对象添加全局配置文件中所有的配置信息
        
        self.SETTINGS_MODULE = settings_module  # 'app.settings'
        mod = importlib.import_module(self.SETTINGS_MODULE)
        # from app import settings  # 导入暴露给用户的自定义配置文件
        for setting in dir(mod):
            if setting.isupper():
                setting_value = getattr(mod, setting)
                setattr(self, setting, setting_value)

Django 模板层

模板语法

  • 只有两种书写格式
    • {{}} 变量相关
    • {% %} 逻辑相关,例如for,if

模板语法之传值

模板语法的传值适用于Python所有的数据类型,包括函数、类

# views.py 下方所有模板语法的演示均参考index数据
from django.shortcuts import render
from datetime import datetime

def index(request):
    # python基本数据类型
    i = 666
    f = 11.11
    s = 'hello world jason egon justin kevin oscar'
    l = [111,222,333,444]
    d = {'username':'jason','password':123,'hobby':['read','study','run',{'username':'jason666'}]}
    t = (111,222,333)
    se = {111,222,333}
    b = True
    b1 = False
    ctime  = datetime.today()
    file_size = 25113366
    
# 传值方式1:利用字典挨个传值
return render(request,'index.html',{'i':i,'f':f,'s':s})
# 传值方式2:简单粗暴  locals()将当前名称空间中所有的变量名全部传递给页面
return render(request,'index.html',locals())

"""
    传值方式1  传值精确 不会造成资源浪费['xcvb/']
    传值方式2  传值粗糙 可能会造成一定的资源浪费 
    ps:为了演示方便 后面就都是用locals()
"""
补充:给HTML页面传递函数名和类名都会自动加括号调用(模板语法不支持额外的传参)

模板语法之获取值

前端获取后端传过来的容器类型的内部元素 统一采用句点符(.)

'''django模板语法取值只能采用句点符(.) '''
索引 键都可以无限制的点点点
<p>{{ d.hobby.3.username }}</p>

模板语法之过滤器

模板语法提供了一些内置方法,以助于快速的处理数据(过滤器最多只能有两个参数)

过滤器:会自动将竖杠左侧的数据当做第一个参数:右侧的当做第二个参数

1.语法:
    -- {{ 变量|过滤器1[[:参数]|...|过滤器n[:参数]] }}
    -- 注:过滤器可以串联操作,可以拥有0个或1个参数
    
2.常见内置filter
    -- 增加   add:num
    -- 字符串长度   length
    -- 默认值   default:'默认值'  # 变量不存在或为空
    -- 全大写   upper
    -- 全小写   lower
    -- 切片   slice:'0:-1'
    -- 将数字转换为文件大小   filesizeformat
    -- 字符串隐藏   truncatechars:13   # 只显示10个字符,后置字符都用...来替代
        --截取文本:truncatewords:3  #只显示三个单词,...不算字符
    -- 时间   date:'Y年-m月-d日'
    -- 转换原意   safe
    转义
    前端
        |safe
    后端
         from django.utils.safestring import mark_safe
         sss1 = mark_safe('<h2>渲染</h2>')
         ps:前端代码也可以在后端写好传入!!!
# 类似于python的内置方法
# 下面的内容,第一行是在前端的代码,第二行是运行的结果
<p>统计长度:{{ s|length }}</p>
 # 统计长度:41

<p>加法运算:{{ i|add:100000000000 }}</p>
 # 加法运算:100000000666

<p>字符串拼接:{{ s|add:'heiheihei' }}</p>
 # 字符串拼接:hello world jason egon justin kevin oscarheiheihei

<p>字符串的切片操作:{{ s|slice:'0:8' }}</p>
 # 字符串的切片操作:hello wo

<p>日期格式:{{ ctime|date:'Y年-m月-d日 H时:i分:s秒' }}</p>
 # 日期格式:2021年-03月-18日 17时:24分:35秒

<p>默认值:左侧对应有值拿左侧:{{ b|default:'哈哈' }}</p>
 # 默认值:左侧对应有值拿左侧:True

<p>默认值:左侧对应没有值拿右侧{{ b1|default:'哈哈' }}</p>
 # 默认值:左侧对应没有值拿右侧:哈哈

<p>将数字格式化成表示文件大小的单位::{{ file_size|filesizeformat }}</p>
 # 将数字格式化成表示文件大小的单位:23.9 MB

<p>截取文本六个字符(三个点也算):{{ s|truncatechars:6 }}</p>
 # 截取文本六个字符(三个点也算):hel...

<p>截取文本(按照空格截取,三个点不算):{{ s|truncatewords:3 }}</p>
 # 截取文本(按照空格截取,三个点不算):hello world jason ...
<p>标签默认不做渲染:{{ h }}</p>
 # 标签默认不做渲染:<h1>困了吗?</h1>

<p>{{ h|safe }}</p>
 # 前端做渲染:困了吗?
    
<p>{{ sss }}</p>
 # <script>alert(123)</script>
    
<p>{{ sss|safe }}</p>
 # 弹窗出现(模拟脚本攻击)
    
<p>{{ sss1 }}</p>
 # 后端做渲染

# (知识点)转义:防止脚本攻击的出现
	前端
    	|safe # 告诉前端这个数据是安全的
    后端
    	h = "<h1>前端做渲染:困了吗?</h1>"
    	sss = "<script>alert(123)</script>"
    	from django.utils.safestring import mark_safe
    	sss1 = mark_safe('<h2>后端做渲染</h2>')
        # mark_safe 标记安全
    ps:前端代码也可以在后端写好传入!!!

模板语法之标签

1.常见内置tag
"""
{{}}  变量相关
{%%}  逻辑相关
"""
  语法:
      -- {% 关键词 参数们 %}
    
  内置tag
    -- 反向解析url   {% url 'namespace:url_name' arg1 arg2 %}
    -- 当前时间now   {% now 'Y-m-d' %}
    -- 起别名with   {% with 'd.hobby.3.username' as name %} 
                               {{ name }}
                    {% endwith %}
    -- Django CSRF认证   {% csrf_token %}

模板语法之分支

语法:
{% if 条件1 %}
    结论1
{% elif 条件2 %}
    结论2
{% else %}
    结论n
{% endif %}

注:
1. if的条件可以添加filter,last
2. 可以嵌套
# 案例
{% for foo in s %}
    {% if forloop.first %}
        <p>这是我的第一次~~</p>
    {% elif forloop.last %}
        <p>这是最后一次了啊~</p>
    {% else %}
        <p>{{ foo }}</p>
    {% endif %}
    
    {% empty %}
        <p>传入的数据是空的</p>
{% endfor %}

模板语法之迭代器

{% for foo in iterate %}
    {{ forloop }}
{% empty %}
    可迭代对象为空
{% endfor %}

注:
1. iterate为可迭代对象
2. iterate可以添加filter
3. forloop变量为存放迭代信息的字典,父级forloop字典,开始索引从0编号或1编号,倒序索引从0编号或1编号,是否是第一次或最后一次循环
4. empty分支会在可迭代对象不存在或空时执行

自定义过滤器、标签、inclusion_tag

自定义过滤器、标签、inclusion_tag必须要有以下三步准备:

  • 1.在应用下创建一个名字必须叫"templatetags"文件夹
  • 2.在上述文件夹内创建一个任意名称的py文件
  • 3.在该py文件内固定先书写以下两句话
from django import template
register = template.Library()

自定义过滤器filter

# 跟默认的过滤器一样 最多只能接受两个参数
from django.template import Library
register = Library()
@register.filter(name='jump')
def owen_jump(value, arg):
    try:
        return value * int(arg)
    except (ValueError, TypeError):
        return ''

自定义标签simple_tag

# 参数可以有多个
from django.template import Library
register = Library()
@register.simple_tag(name='add_two')
def owen_add(arg1, arg2):
    try:
        return int(arg1) + int(arg2)
    except (ValueError, TypeError):
        try:
            return arg1 + arg2
        except Exception:
            return ''

自定义inclusion_tag

内部原理

  • 先定义一个方法
  • 在页面上调用这个方法,并且可以传值
  • 该方法会生成一些数据然后传递给一个html页面
  • 之后将渲染好的结果放到调用的位置
    inclusion_tag 应用场景:当html页面某个区域需要反复使用并且数据不是固定的
@register.inclusion_tag('login.html',name='my_inclusion_tag')
def func2(n):
    l = []
    for i in range(1,n+1):
        l.append('第%s页'%i)
    return locals() # 将当前局部名称空间的所有名字传给login.html页面

# login.html小页面专门生成无序列表
<ul>
    {% for foo in l %}
        <li>{{ foo }}</li>
    {% endfor %}
</ul>


# 前端使用index.html展示渲染效果:
{% my_inclusion_tag 4 %}
{% my_inclusion_tag 2 %}

# 渲染结果
    第1页
    第2页
    第3页
    第4页

    第1页
    第2页

模板导入

# 类似于后端导模块 想要什么局部页面直接导入即可

{% include 'xxx.html' %}

模板的继承

先使用block划定区域
母版
    {% block 区域名称 %}
    {% endblock %}
子版
    {% extends 'home.html' %}
    {% block 区域名称 %}
    {% endblock %}
  
母版在划定区域的时候一般都应该有三个区域
   css区域
   html文档区域
   js区域
   ps:目的是为了让子版具有独立的css js等 增加扩展性
    {% block css %}

    {% endblock %}
    
    {% block content %}

    {% endblock %}
    
    {% block js %}

    {% endblock %}
 
ps:子版也可以继续使用母版划定区域内的内容
    {{ block.super }}
posted @ 2021-11-30 17:13  沈忻凯  阅读(50)  评论(0)    收藏  举报