小程序开发笔记(二)Django模板

2022/3/18 pythonDjango

# 一、映射关系

在Django项目中与manage.py同级下创建一个名为templates的文件夹,其中用来存放html文件,作为View层

该文件夹中的html文件与views.py和urls.py文件存在对应关系

202203171150205

首先需要在settings.py中对模板路径进行修改,配置相对路径:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        # 配置相关html文件夹
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

其中'DIRS': [os.path.join(BASE_DIR, 'templates')]中的templates对应的就是存放html文件的文件夹

然后由于后续使用到了模板,所以在urls.py文件中使用render代替之前使用的HttpResponse,render可以使用字典context作为参数

from django.shortcuts import render

def test(request):
    context = {'variable': 'variable01'}
    return render(request, 'test.html', context)

# 二、模板标签

  • 基本语法
views: {"HTML变量名称": "views变量"}
HTML: {{ HTML变量名称 }}

Django中可以使用三种参数作为模板

  • 变量
  • 列表:templates 中的 runoob.html中,可以用.索引下标取出对应的元素
  • 字典:templates 中的 runoob.html中,可以用.键取出对应的值

views.py

from django.shortcuts import render

def test(request):
    context = {
        # 变量
        'variable': 'variable01',
        # 列表
        'list': ['list_var01', 'list_var02'],
        # 字典
        'dictionary': {'name': 'dict_name', 'age': '20'}
    }
    return render(request, 'test.html', context)

test.py

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>变量:{{ variable }}</h3>
    <h3>列表全部展示:{{ list }}</h3>
    <h3>列表索引:{{ list.0 }},{{ list.1 }}</h3>
    <h3>字典按键展示:name->{{ dictionary.name }},age->{{ dictionary.age }}</h3>
</body>
</html>

# 三、过滤器

过滤器 描述
upper 以大写方式输出
add 给value加上一个数值
addslashes 单引号加上转义号
capfirst 第一个字母大写
center 输出指定长度的字符串,把变量居中
cut 删除指定字符串
date 格式化日期
default 如果值不存在,则使用默认值代替
default_if_none 如果值为None, 则使用默认值代替
dictsort 按某字段排序,变量必须是一个dictionary
dictsortreversed 按某字段倒序排序,变量必须是dictionary
divisibleby 判断是否可以被数字整除
escape 按HTML转义,比如将”<”转换为”&lt”
filesizeformat 增加数字的可读性,转换结果为13KB,89MB,3Bytes等
first 返回列表的第1个元素,变量必须是一个列表
floatformat 转换为指定精度的小数,默认保留1位小数
get_digit 从个位数开始截取指定位置的数字
join 用指定分隔符连接列表
length 返回列表中元素的个数或字符串长度
length_is 检查列表,字符串长度是否符合指定的值
linebreaks <p><br>标签包裹变量
linebreaksbr <br/>标签代替换行符
linenumbers 为变量中的每一行加上行号
ljust 输出指定长度的字符串,变量左对齐
lower 字符串变小写
make_list 将字符串转换为列表
pluralize 根据数字确定是否输出英文复数符号
random 返回列表的随机一项
removetags 删除字符串中指定的HTML标记
rjust 输出指定长度的字符串,变量右对齐
slice 切片操作, 返回列表
slugify 在字符串中留下减号和下划线,其它符号删除,空格用减号替换
stringformat 字符串格式化,语法同python
time 返回日期的时间部分
timesince 以“到现在为止过了多长时间”显示时间变量
timeuntil 以“从现在开始到时间变量”还有多长时间显示时间变量
title 每个单词首字母大写
truncatewords 将字符串转换为省略表达方式
truncatewords_html 同上,但保留其中的HTML标签
urlencode 将字符串中的特殊字符转换为url兼容表达方式
urlize 将变量字符串中的url由纯文本变为链接
wordcount 返回变量字符串中的单词数
yesno 将布尔变量转换为字符串yes, no 或maybe

# 四、标签

# 4.1if/else标签

基本语法格式如下:

{% if condition %}
     ... display
{% endif %}

或者:

{% if condition1 %}
   ... display 1
{% elif condition2 %}
   ... display 2
{% else %}
   ... display 3
{% endif %}

根据条件判断是否输出。if/else 支持嵌套

{% if %} 标签接受 and , or 或者 not 关键字来对多个变量做判断 ,或者对变量取反( not ),例如:

{% if athlete_list and coach_list %}
     athletes 和 coaches 变量都是可用的。
{% endif %}

# 4.2for标签

{% for %} 允许我们在一个序列上迭代

与 Python 的 for 语句的情形类似,循环语法是 for X in Y ,Y 是要迭代的序列而 X 是在每一个特定的循环中使用的变量名称

每一次循环中,模板系统会渲染在{% for %}和{% endfor %}之间的所有内容

例如,给定一个运动员列表 athlete_list 变量,我们可以使用下面的代码来显示这个列表:

<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% endfor %}
</ul>

给标签增加一个 reversed 使得该列表被反向迭代:

{% for athlete in athlete_list reversed %}
...
{% endfor %}

在 {% for %} 标签里可以通过 变量获取循环序号

  • forloop.counter: 顺序获取循环序号,从 1 开始计算
  • forloop.counter0: 顺序获取循环序号,从 0 开始计算
  • forloop.revcounter: 倒序获取循环序号,结尾序号为 1
  • forloop.revcounter0: 倒序获取循环序号,结尾序号为 0
  • forloop.first(一般配合if标签使用): 第一条数据返回 True,其他数据返回 False
  • forloop.last(一般配合if标签使用): 最后一条数据返回 True,其他数据返回 False

可以嵌套使用 {% for %} 标签:

{% for athlete in athlete_list %}
    <h1>{{ athlete.name }}</h1>
    <ul>
    {% for sport in athlete.sports_played %}
        <li>{{ sport }}</li>
    {% endfor %}
    </ul>
{% endfor %}

# 4.3ifequal/ifnotequal标签

{% ifequal %} 标签比较两个值,当他们相等时,显示在 {% ifequal %} 和 {% endifequal %} 之中所有的值

下面的例子比较两个模板变量 user 和 currentuser :

{% ifequal user currentuser %}
    <h1>Welcome!</h1>
{% endifequal %}

和 {% if %} 类似, {% ifequal %} 支持可选的 {% else%} 标签:

{% ifequal section 'sitenews' %}
    <h1>Site News</h1>
{% else %}
    <h1>No News Here</h1>
{% endifequal %}

# 4.4注释标签

Django 注释使用 {# #}

{# 这是一个注释 #}

# 4.5include标签

{% include %} 标签允许在模板中包含其它的模板的内容

下面这个例子都包含了 nav.html 模板:

{% include "nav.html" %}

# 4.6csrf_token标签

csrf_token 用于form表单中,作用是跨站请求伪造保护

如果不用{% csrf_token %}标签,在用 form 表单时,要再次跳转页面会报403权限错误。

用了{% csrf_token %}标签,在 form 表单提交数据时,才会成功。

解析:

首先,向服务器发送请求,获取登录页面,此时中间件 csrf 会自动生成一个隐藏input标签,该标签里的 value 属性的值是一个随机的字符串,用户获取到登录页面的同时也获取到了这个隐藏的input标签。

然后,等用户需要用到form表单提交数据的时候,会携带这个 input 标签一起提交给中间件 csrf,原因是 form 表单提交数据时,会包括所有的 input 标签,中间件 csrf 接收到数据时,会判断,这个随机字符串是不是第一次它发给用户的那个,如果是,则数据提交成功,如果不是,则返回403权限错误。

# 五、自定义过滤器/标签

  • 在应用目录下创建 templatetags目录(与templates目录同级,目录名只能是templatetags)。
HelloWorld/
|-- HelloWorld
|   |-- __init__.py
|   |-- __init__.pyc
|   |-- settings.py
...
|-- manage.py
`-- templatetags
`-- templates
  • 在 templatetags 目录下创建任意 py 文件,如:my_tags.py

  • my_tags.py 文件代码如下:

from django import template

# register的名字是固定的,不可以改变
register = template.Library()
  • 修改settings.py配置,添加libraries配置:
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        # 配置相关html文件夹
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
            "libraries": {
                'my_tags': 'templatetags.my_tags'
            }
        },
    },
]
  • 利用装饰器@register.filter自定义过滤器。

**注意:**装饰器的参数最多只能有 2 个

@register.filter
def my_filter(v1, v2):
    return v1 * v2
  • 利用装饰器@register.simple_tag自定义标签。
@register.simple_tag
def my_tag1(v1, v2, v3):
    return v1 * v2 * v3
  • 在使用自定义标签和过滤器前,要在html文件body的最上方中导入该py文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% load my_tags %}
    <h1>自定义过滤器</h1>
    <h3>{{ 11|my_filter:22 }}</h3>

    <h1>自定义标签</h1>
    <h3>{% my_tag 11 22 33 %}</h3>
</body>
</html>
  • 语义化标签,在my_tags.py文件中使用mark_safe方法,使标签语义化
from django.utils.safestring import mark_safe

# register的名字是固定的,不可以改变
register = template.Library()

# 语义化标签
@register.simple_tag
def my_html(v1, v2):
    temp_html = "<input type='text' id='%s' class='%s' />" %(v1, v2)
    return mark_safe(temp_html)

html调用语义化标签

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% load my_tags %}
    <h1>变量</h1>
    <h3>变量:{{ variable }}</h3>
    <h3>列表全部展示:{{ list }}</h3>
    <h3>列表索引:{{ list.0 }},{{ list.1 }}</h3>
    <h3>字典按键展示:name->{{ dictionary.name }},age->{{ dictionary.age }}</h3>

    <h1>过滤器</h1>
    <h3>{{ variable|upper }}</h3>
    <h3>{{ variable|lower }}</h3>
    <h3>{{ variable|length }}</h3>
    <h3>{{ variable|first|upper }}</h3>

    <h1>标签</h1>
    <ul>
        {% for i in list %}
            <h3>{{ i }}</h3>
        {% endfor %}
    </ul>

    <h1>自定义过滤器</h1>
    <h3>{{ 11|my_filter:22 }}</h3>

    <h1>自定义标签</h1>
    <h3>{% my_tag 11 22 33 %}</h3>

    <h1>语义化标签</h1>
    {% my_html "zzz" "xxx" %}
</body>
</html>

# 六、静态文件配置

  • 在项目根目录下创建 statics 目录。

202203172013889

  • 在 settings 文件的最下方配置添加以下配置:
STATIC_URL = '/static/' # 别名 
STATICFILES_DIRS = [ 
    os.path.join(BASE_DIR, "statics"), 
]
  • 在 statics 目录下创建 css 目录,js 目录,images 目录,plugins 目录, 分别放 css文件,js文件,图片,插件。

  • 把 bootstrap 框架放入插件目录 plugins。

  • 在 HTML 文件的 head 标签中引入 bootstrap。

注意:此时引用路径中的要用配置文件中的别名 static,而不是目录 statics

<link rel="stylesheet" href="/static/plugins/bootstrap-5.1.3-dist/css/bootstrap.css">

在模板中使用需要加入{% load static %}代码,以下实例我们从静态目录中引入图片