1.django模板配置
1.1 Django模板概述
作为一个Web框架,Django需要一种方便的方式来动态生成HTML。最常用的方法依赖于模板。模板包含所需HTML输出的静态部分以及描述如何插入动态内容的特殊语法。
对模板引擎的一般支持和Django模板语言的实现都存在于 django.template 命名空间中
1.2 django默认模板
- 配置
在settings中配置:
# 配置模板
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',# 使用默认的Django的模板
'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',
],
},
},
]
笔记:
- BACKEND:是实现Django模板后端API的模板引擎类的路径。内置是django.template.backends.django.DjangoTemplates和 django.template.backends.jinja2.Jinja2(使用这个需要额外安装jinja2库)
- DIRS :按搜索顺序定义引擎应该查找模板源文件的目录列表
- APP_DIRS:告诉引擎是否应该在已安装的应用程序中查找模板,每个后端为其模板应存储在的应用程序内的子目录定义一个常规名称。
- OPTIONS:包含后端特定的设置
1.3 用法
-
get_template
该函数使用给定名称加载模板并返回一个 Template对象,找到第一个匹配的模板即返回
template = get_template('story_detail.html')
Django将要查找的文件,依次为:
- /home/html/example.com/story_detail.html('django’引擎)
- /home/html/default/story_detail.html('django’引擎)
- /home/html/jinja2/story_detail.html('jinja2’引擎)
示例:
# 最常用的render
from django.shortcuts import render
def my_view(request):
# View code here...
return render(request, 'myapp/index.html', {
'foo': 'bar',
}, content_type='application/xhtml+xml')
# 相当于基础的get_template:
from django.http import HttpResponse
from django.template import loader
def my_view(request):
# View code here...
template = loader.get_template('myapp/index.html')
context = {'foo': 'bar'}
# 注意,这个 render 和 快捷键 render 不是一个对象
return HttpResponse(template.render(context, request), content_type='application/xhtml+xml')
-
select_template
select_template() 用法类似 get_template() ,除了它需要一个模板名称的列表。它按顺序尝试每个名称并返回存在的第一个模板
template = select_template(['story_253_detail.html','story_detail.html'])
Django将要查找的文件,依次为:
- /home/html/example.com/story_253_detail.html('django’引擎)
- /home/html/default/story_253_detail.html('django’引擎)
- /home/html/jinja2/story_253_detail.html('jinja2’引擎)
- /home/html/example.com/story_detail.html('django’引擎)
- /home/html/default/story_detail.html('django’引擎)
- /home/html/jinja2/story_detail.html('jinja2’引擎)
2.Django模板渲染变量
Django模板只是一个文本文档或使用Django模板语言标记的Python字符串。一些结构被模板引擎识别和解释,主要的是变量( {{ 变量 }} )和标签( {% 标签 %} )。
2.1 django中模板渲染配置
其中也包含模板渲染变量的测试
首先创建一个主应用,子应用。在子应用中创建一个templates文件夹并在下面创建一个template_app文件夹,还有创建一个urls.py路由文件。
配置主应用中的settings
INSTALLED_APPS = [
'template_app',
]
import os
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates')],
配置子应用的路由地址(主应用的urls中)
from django.contrib import admin
from django.urls import path
from django.urls.conf import include
urlpatterns = [
path('admin/', admin.site.urls),
path('template_app/', include('template_app.urls'))
]
以上配置基本完成
开始测试模板渲染的变量
子应用url配置
from django.contrib import admin
from django.urls import path
from django.urls.conf import include
from . import views
urlpatterns = [
path('var_test/', views.var_test)
]
子应用的views
from django.shortcuts import render
# Create your views here.
def var_test(request):
# 传递变量给模板
context_name = {
"first_name":'tom',
"last_name":"zhang"
}
return render(request, 'template_app/var_test.html', context_name) # 返回模板携带变量
模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
first_name:{{first_name}} <br>
last_name: {{last_name}} <br>
</body>
</html>
3.django模板渲染实体_字典_列表
- 变量
一个变量从上下文中输出一个值,这是一个类似字典的对象将键映射到值。 - 标签
创建数据模型
from django.db import models
# Create your models here.
class Person(models.Model):
pname = models.CharField(max_length=30)
age = models.IntegerField()
password = models.CharField(max_length=8)
sex = models.CharField(max_length=5)
salary = models.FloatField()
配置数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'template_study',
"HOST":'127.0.0.1',
"USER": 'root',
"PASSWORD": 'root',
'PORT':3306
}
}
迁移数据库命令
python manage.py makemigrations template_app
python manage.py migrate template_app
views视图
from django.shortcuts import render
from template_app.models import *
# 在页面中渲染实体_字典_列表
def data_test(request,id):
p = Person.objects.get(pk=id)
person_list = Person.objects.all()
address_dict = {
'bj':'北京',
'sh':'上海',
'gz':'广州'
}
return render(request, 'template_app/data_test.html',{'person':p,'person_list':person_list, 'address_dict':address_dict})
template模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>在页面中渲染实体_字典_列表</title>
</head>
<body>
<p>实体的渲染</p>
<ul>
<li>{{ person.pname }}</li>
<li>{{ person.age }}</li>
<li>{{ person.sex }}</li>
<li>{{ person.salary }}</li>
</ul>
<p>列表的渲染</p>
{{ person_list.0.pname }}
{{ person_list.1.pname }}
{{ person_list.2.pname }}
{{ person_list.3.pname }}
{{ person_list.4.pname }}
<p>字典的渲染</p>
{{ address_dict.bj }} <br>
{{ address_dict.sh }} <br>
{{ address_dict.gz }} <br>
</body>
</html>
url
from django.contrib import admin
from django.urls import path
from django.urls.conf import include
from . import views
urlpatterns = [
path('data_test/<int:id>/', views.data_test)
]
4.标签csrf_token的使用
测试代码思路:我们创建一个views视图,然后返回一个模板,内容是form表单的输入账号密码。点击按钮只会,需要跳转到一个登录成功的新路由中。这时候,就需要我们使用csrf_token防跨域攻击
无参数标签 csrf_token ,这个标签是用于html进行 form 表单提交时,包含一个 随机变化的字符串,在html页面中,其实就是一个 inputtype=‘hidden’ 作用是用于防止跨域攻击
{% csrf_token %}
传参的标签 cycle , 参数 ‘odd’ ‘even’ ,空格间隔
标签本身也支持 关键字参数 {% 标签 key1=‘value’ key1=‘even’ %}
{% cycle ‘odd’ ‘even’ %}
代码展示
views
from django.shortcuts import render, HttpResponse
from template_app.models import *
def login_html(request):
return render(request, "template_app/login.html")
def login(request):
return HttpResponse("登录成功")
urls
from django.contrib import admin
from django.urls import path
from django.urls.conf import include
from . import views
urlpatterns = [
path('login_html/',views.login_html),
path('login/',views.login,name="login")
]
template模板—— csrf_token
<body>
<form action="/template_app/login/" method="POST">
{% csrf_token %}
用户名: <input type="text" name="pname"> <br>
密码: <input type="password" name="password"> <br>
<input type="submit" value="登录">
</form>
</body>
</html>
5.标签
5.1 标签之for if firstof的使用
方法概述
- firstof
输出不是False的第一个参数,所有参数都为False,则什么都不输出
for循环在循环中设置了许多变量:
变量 | 描述 |
---|---|
forloop.counter | 循环的当前迭代(1索引) |
forloop.counter0 | 循环的当前迭代(0索引) |
forloop.revcounter | 循环结束时的迭代次数(1索引) |
forloop.revcounter0 | 循环结束时的迭代次数(0索引) |
forloop.first | 如果这是通过循环的第一次,则为真 |
forloop.last | 如果这是通过循环的最后一次,则为真 |
forloop.parentloop | 对于嵌套循环,这是围绕当前循环的循环 |
views
def login_html(request):
return render(request, "template_app/login.html")
def login(request):
# 从form 表单中获取数据(POST)
data_dict = request.POST
pname = data_dict.get('pname')
password = data_dict.get('password')
# 根据用户名和密码查询人
persons = Person.objects.filter(pname=pname, password=password)
if persons:
# 跳转到Person列表(重定向)
return redirect('find_person')
else:
# 不通过验证,返回登录页面
return render(request,'template_app/login.html')
def find_person(request):
person_list = Person.objects.all()
return render(request,'template_app/person_list.html',{'person_list':person_list})
urls
from django.contrib import admin
from django.urls import path
from django.urls.conf import include
from . import views
urlpatterns = [
path('login_html/',views.login_html),
path('login/',views.login,name="login"),
path('find_person/',views.find_person, name="find_person")
]
templates
<body>
<table>
<tr>
<td>序号</td>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
<td>薪资</td>
<td>薪资等级</td>
</tr>
<!-- 标签之for循环、if判断、empty(for循环中无数据)的使用 -->
{% for person in person_list %}
<tr class="{% cycle 'odd' 'even' %}">
<td>{{ forloop.counter }}</td>
<td>{{ person.pname }}</td>
<td>{{ person.age }}</td>
<td>{{ person.sex }}</td>
<td>{{ person.salary }}</td>
{% if person.salary >= 10000 %}
<td>高新</td>
{% elif person.salary >= 5000 %}
<td>中薪</td>
{% else %}
<td>低薪</td>
{% endif %}
</tr>
{% empty %}
没有查询到数据
{% endfor %}
</table>
----------firstof{% firstof 0 2 3 %}-------
</body>
</html>
5.2 标签之url的使用
如何使用应用名? 如何在template中使用a标签跳转路由?如何跳转路由携带参数?
template:login
<body>
<!-- <form action="/template_app/login/" method="POST"> 根据地址来跳转 -->
<!-- 根据url标签,跳转路由(根据路由取得名称跳转) -->
<form action="{% url 'template_name:login'%}" method="POST">
{% csrf_token %}
用户名: <input type="text" name="pname"> <br>
密码: <input type="password" name="password"> <br>
<input type="submit" value="登录">
</form>
</body>
template:person_list
----------url测试标签(跳转的是视图)---------- <br>
<a href="{% url 'template_name:url_test' 10 %}">url测试跳转视图</a>
urls
from django.contrib import admin
from django.urls import path
from django.urls.conf import include
from . import views
app_name = "template_name"
urlpatterns = [
path('login_html/',views.login_html),
path('login/',views.login,name="login"),
path('find_person/',views.find_person, name="find_person"),
path('url_test/<int:num>/', views.url_test, name="url_test")
]
views:
from django.shortcuts import render, HttpResponse, redirect
from template_app.models import *
def login_html(request):
return render(request, "template_app/login.html")
def login(request):
# 从form 表单中获取数据(POST)
data_dict = request.POST
pname = data_dict.get('pname')
password = data_dict.get('password')
# 根据用户名和密码查询人
persons = Person.objects.filter(pname=pname, password=password)
if persons:
# 跳转到Person列表(重定向)
return redirect('template_name:find_person')
else:
# 不通过验证,返回登录页面
return render(request,'template_app/login.html')
def find_person(request):
person_list = Person.objects.all()
return render(request,'template_app/person_list.html',{'person_list':person_list})
def url_test(request,num):
return HttpResponse(f"url测试标签成功!{num}")
5.3 标签widthratio、with的使用
widthratio:乘法和除法(具体使用方法笔记写在代码中)
with:简单的名称缓存复杂变量,当访问多次耗时的方法(例如操作数据库的方法):
<body>
<table>
<tr>
<td>序号</td>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
<td>薪资</td>
<td>薪资等级</td>
<td>年薪</td>
<td>年薪调用方法</td>
<td>width的使用</td>
</tr>
<!-- 标签之for循环、if判断、empty(for循环中无数据)的使用 -->
{% for person in person_list %}
<tr class="{% cycle 'odd' 'even' %}">
<td>{{ forloop.counter }}</td>
<td>{{ person.pname }}</td>
<td>{{ person.age }}</td>
<td>{{ person.sex }}</td>
<td>{{ person.salary }}</td>
{% if person.salary >= 10000 %}
<td>高新</td>
{% elif person.salary >= 5000 %}
<td>中薪</td>
{% else %}
<td>低薪</td>
{% endif %}
<!-- ----------widthratio----------------------- -->
<!-- widthratio乘除法:共3位数字,num1/num2*num3 -->
<td>{% widthratio person.salary 1 12 %}</td>
<td>{{ person.year_salary }}</td>
<td>
{% with new_age=person.age %}
{{ new_age }}
{% endwith %}
</td>
</tr>
{% empty %}
没有查询到数据
{% endfor %}
模型model
from django.db import models
# Create your models here.
class Person(models.Model):
pname = models.CharField(max_length=30)
age = models.IntegerField()
password = models.CharField(max_length=8)
sex = models.CharField(max_length=5)
salary = models.FloatField()
def year_salary(self):
return self.salary * 12
5.4 过滤器的使用
<body>
-----------length(计算字符串长度)------------------ <br>
msg:{{msg|length}} <br>
{% if msg|length >= 10 %}
msg的长度大于等于10 <br>
{%endif%}
-----------add(加法)--------------------- <br>
num+10:{{num|add:"10"}} <br>
-----------divisibleby(是否能整除于num)--------------------- <br>
{{ num|divisibleby:"2" }} <br>
-----------addslashes(单引号前加\)--------------------- <br>
{{ value|addslashes }} <br>
-----------capfirst(首字母大写)--------------------- <br>
{{ msg|capfirst }} <br>
-----------center(将值置于给定宽度的字段中)--------------------- <br>
{{ msg|center:"50" }} <br>
-----------cut(去掉对应的值)--------------------- <br>
{{ value|cut:" " }} <br>
-----------日期时间--------------------- <br>
{{ birthday }}
{{ value|date:"Y-m-d H:i:s" }}
</body>
5.5 include标签
主template
<body>
<!-- 包含header.html -->
<!-- 若视图和模板同时传递了参数,会显示模板中的数据 -->
<!-- only: 若存在only视图未传递参数,不管模板是否存在,直接使用默认值 -->
{% include "template_app/header.html" with name='测试是否会覆盖视图传递的数据' only %}
<!-- 包含footer.html -->
{% include "template_app/footer.html" %}
</body>
header
<body>
<ul>
<li>新闻</li>
<li>娱乐</li>
<li>热点</li>
<li>{{name}}</li>
<!-- 传递默认值 -->
<li>{{age|default:18}}</li>
</ul>
</body>
footer
<body>
<p>关于百度About Baidu使用百度前必读帮助中心企业推广京公网安备11000002000001号京ICP证030173号信息网络传播视听节目许可证</p>
</body>
views
def include_test(request):
return render(request, 'template_app/include_test.html',{"name":"关注",'age':30})
5.6 静态文件的使用
<!DOCTYPE html>
<html lang="en">
<!-- 引入静态文件 -->
{% load static %}
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引入css -->
<link rel="stylesheet" href="{% static 'template_app/css/mystyle.css' %}">
<script type="text/javascript" src="{% static 'template_app/js/js_test.js' %}"></script>
</head>
<body>
<p>静态文件测试</p>
<p class="pstyle">显示图片</p>
<img src="{% static 'template_app/imgs/1.jpg' %}">
<button onclick="click_func()">点我</button>
</body>
</html>
6. 模板继承
Django模板引擎中最强大,也是最复杂的部分是模板继承。模板继承允许构建一个基本“骨架”模板,其中包含您网站的所有常见元素,并定义子模板可以覆盖的 blocks
继承的技巧:
- 如果在模板中使用,{% extends %}必须是该模板中的第一个模板标签。否则模板继承将不起作用。
- 基本模板中的越多{% block %}标签越好。子模板不必定义所有父块,因此可以在多个块中填写合理的默认值
- 如果发现自己在多个模板中复制了内容,则可能意味着您应该将该内容移至父模板的 {% block %} 中
- 如果需要从父模板中获取块的内容,则使用 {{ block.super }}
子模板
{% extends "template_app/base.html" %}
<!-- 模板继承,修改父模板的参数 -->
{% block title %}
extends_testhtml
{% endblock %}
{% load static %}
{% block css %}
<link rel="stylesheet" href="{% static 'template_app/css/mystyle.css' %}">
{%endblock%}
{% block js %}
<script type="text/javascript" src="{% static 'template_app/js/js_test.js' %}"></script>
{% endblock %}
{% block context %}
<p class="pstyle">样式测试</p>
<button onclick="click_func()">点击</button>
{% endblock %}
父模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}basehtml{% endblock %}</title>
{% block css %}{%endblock%}
{% block js %}{%endblock%}
</head>
<body>
{% include "template_app/header.html" with name="模板继承base.html" %}
{%block context%}{%endblock%}
{% include "template_app/footer.html" %}
</body>
</html>