python-Django二
- 使用Django的情况、在建表的时候应该先建一个id主键
Django表关联查询
# 项目目录 --> employee --> modules.py
from django.db import models
# Create your models here.
'''
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` smallint(6) NOT NULL DEFAULT '1' COMMENT 'M=1, F=2',
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
'''
class Gender(models.IntegerChoices):
MALE = 1, '男' # 调用的时候 .get_gender_display() 会返回 '男'
FEMALE = 2, '女' # 调用的时候 .get_gender_display() 会返回 '女'
# 类、类属性
# 表、字段
# 每一行数据库的数据 对应类的实例
class employee(models.Model): # Model 基类做了很多不可见的工作
class Meta:
db_table = 'employees'
emp_no = models.IntegerField(primary_key=True,verbose_name='工号') # 主键,其中 IntergerField 是字段类型,字段类型为整数,verbose_name 是字段的别名只在django的后台管理系统中显示,不会影响数据库表结构,primary_key=True 是主键
birth_date = models.DateField(verbose_name='出生日期') # 出生日期 DateField 是字段类型,字段类型为日期
first_name = models.CharField(max_length=14,verbose_name='名字') # 名字 CharField 是字段类型,字段类型为字符串,max_length=14 是最大长度
last_name = models.CharField(max_length=16,verbose_name='姓氏') # 姓氏 CharField 是字段类型,字段类型为字符串,max_length=16 是最大长度
gender = models.SmallIntegerField(choices=Gender.choices ,verbose_name='性别') # 性别 SmallIntegerField 是字段类型,字段类型为整数,choices 是选项,verbose_name 是字段的别名只在django的后台管理系统中显示,不会影响数据库表结构
hire_date = models.DateField()
# salary_set 表示关联的对象们~ 多个的
@property # property 装饰器,将方法伪装成属性
def name(self):
return "[{} {}]".format(self.last_name,self.first_name)
def __repr__(self):
return "<E {} {}>".format(self.emp_no,self.name)
__str__ = __repr__ # 这个是打印给自己调试时看着方便
'''以上表的所有字段已经定义完'''
'''
CREATE TABLE `salaries` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`id`),
KEY `salaries_ibfk_1` (`emp_no`),
CONSTRAINT `salaries_ibfk_1` FOREIGN KEY (`emp_no`) REFERENCES `employees` (`emp_no`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=42 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;
'''
class Salary(models.Model):
class Meta:
db_table = 'salaries'
# emp_no = models.AutoField(primary_key=True,) # 如果表中没有主键,那么django会自动创建一个id字段主键,这个主键是自增的
# emp_no 管理对象表示关系,关联Employee实例了
# emp_no 这个是字段属性
# emp_no_id 关联到对方的一个对象
emp_no = models.ForeignKey('employee',on_delete=models.CASCADE,verbose_name='工号',db_column='emp_no',related_name='salaries') # 外键,关联employee表的emp_no字段,on_delete=models.CASCADE 是级联删除,verbose_name 是字段的别名只在django的后台管理系统中显示,不会影响数据库表结构,db_column 是数据库表的字段名
salary = models.IntegerField(verbose_name='工资')
from_date = models.DateField(verbose_name='开始日期')
to_date = models.DateField(verbose_name='结束日期')
def __str__(self):
return "<S {},{},{}>".format(self.pk,self.emp_no_id,self.salary)
# 注意加上self.emp_no 实的emp_no属性、这个属性是留给了关联的employee对象的,有emp_no,但没有name没有,因此要多次查询
- 调试
# 项目目录 --> t1.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'salary.settings')
django.setup(set_prefix=False) # 从wsgi.py 里找 --> get_wsgi_application --> django.setup(set_prefix=False)
'''以上属于固定写法,开始写自己的测试代码'''
from employee.models import employee,Salary
# print(employee.objects.all()) # 查询所有数据,<QuerySet []> 返回一个空的查询集,<employee: employee object (10020)> ,将每一行数据都封装成了一个实例对象
emgr = employee.objects
smgr = Salary.objects
# 10002员工的工资
# for x in smgr.filter(emp_no=10002):
# print(type(x),x)
# print(x.id,x.pk, x.emp_no_id, x.salary)
# print(x.emp_no.name)
# 1. 从工资表查, 多端 , 不合适, 反方向查不是一个好的选择,因为要多次查询
# 10002员工的工资
emp = emgr.get(pk=10002) # 这样拿到的是一个员工对象
# print(*Salary.__dict__.items(),sep='\n')
print(emp.pk, emp.name)
# print(emp.salary_set.all())
print(emp.salaries.all()) # 因此尽可能的要先查一端,再查多端
x = smgr.filter(salary__gt=60000).values('emp_no').distinct()
print(x)
print(emgr.filter(pk__in=map(lambda x:x.get('emp_no'),x))) # 这里的x是一个字典的列表,map(lambda x:x.get('emp_no'),x) 是一个生成器,返回的是一个emp_no的列表
print(emgr.filter(pk__in=[i.get('emp_no') for i in x])) # 这里的x是一个字典的列表,[i.get('emp_no') for i in x] 是一个列表,返回的是一个emp_no的列表
- raw的使用
x = mgr.raw('''
SELECT
employees.emp_no,
employees.first_name,
employees.last_name,
salaries.salary
FROM
employees
INNER JOIN salaries ON salaries.emp_no = employees.emp_no
WHERE
salaries.salary > 60000
''')
print(type(x),x)
for i in x:
print(type(i),i, i.salary)
多对多的关系
# 项目目录 --> employee --> 编辑 models.py
from django.db import models
# Create your models here.
'''
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` smallint(6) NOT NULL DEFAULT '1' COMMENT 'M=1, F=2',
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
'''
class Gender(models.IntegerChoices):
MALE = 1, '男' # 调用的时候 .get_gender_display() 会返回 '男'
FEMALE = 2, '女' # 调用的时候 .get_gender_display() 会返回 '女'
# 类、类属性
# 表、字段
# 每一行数据库的数据 对应类的实例
class employee(models.Model): # Model 基类做了很多不可见的工作
class Meta:
db_table = 'employees'
emp_no = models.IntegerField(primary_key=True,verbose_name='工号') # 主键,其中 IntergerField 是字段类型,字段类型为整数,verbose_name 是字段的别名只在django的后台管理系统中显示,不会影响数据库表结构,primary_key=True 是主键
birth_date = models.DateField(verbose_name='出生日期') # 出生日期 DateField 是字段类型,字段类型为日期
first_name = models.CharField(max_length=14,verbose_name='名字') # 名字 CharField 是字段类型,字段类型为字符串,max_length=14 是最大长度
last_name = models.CharField(max_length=16,verbose_name='姓氏') # 姓氏 CharField 是字段类型,字段类型为字符串,max_length=16 是最大长度
gender = models.SmallIntegerField(choices=Gender.choices ,verbose_name='性别') # 性别 SmallIntegerField 是字段类型,字段类型为整数,choices 是选项,verbose_name 是字段的别名只在django的后台管理系统中显示,不会影响数据库表结构
hire_date = models.DateField()
# salary_set 表示关联的对象们~ 多个的
@property # property 装饰器,将方法伪装成属性
def name(self):
return "[{} {}]".format(self.last_name,self.first_name)
def __repr__(self):
return "<E {} {}>".format(self.emp_no,self.name)
__str__ = __repr__ # 这个是打印给自己调试时看着方便
'''以上表的所有字段已经定义完'''
'''
CREATE TABLE `salaries` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`id`),
KEY `salaries_ibfk_1` (`emp_no`),
CONSTRAINT `salaries_ibfk_1` FOREIGN KEY (`emp_no`) REFERENCES `employees` (`emp_no`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=42 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;
'''
class Salary(models.Model):
class Meta:
db_table = 'salaries'
# emp_no = models.AutoField(primary_key=True,) # 如果表中没有主键,那么django会自动创建一个id字段主键,这个主键是自增的
# emp_no 管理对象表示关系,关联Employee实例了
# emp_no 这个是字段属性
# emp_no_id 关联到对方的一个对象
emp_no = models.ForeignKey('employee',on_delete=models.CASCADE,verbose_name='工号',db_column='emp_no',related_name='salaries') # 外键,关联employee表的emp_no字段,on_delete=models.CASCADE 是级联删除,verbose_name 是字段的别名只在django的后台管理系统中显示,不会影响数据库表结构,db_column 是数据库表的字段名
salary = models.IntegerField(verbose_name='工资')
from_date = models.DateField(verbose_name='开始日期')
to_date = models.DateField(verbose_name='结束日期')
def __str__(self):
return "<S {},{},{}>".format(self.pk,self.emp_no_id,self.salary)
# 注意加上self.emp_no 实的emp_no属性、这个属性是留给了关联的employee对象的,有emp_no,但没有name没有,因此要多次查询
'''
CREATE TABLE `departments` (
`dept_no` char(4) NOT NULL,
`dept_name` varchar(40) NOT NULL,
PRIMARY KEY (`dept_no`),
UNIQUE KEY `dept_name` (`dept_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;
'''
class Department(models.Model):
class Meta:
db_table = 'departments'
dept_no = models.CharField(max_length=4, primary_key=True)
dept_name = models.CharField(max_length=40,unique=True)
def __str__(self):
return "<D {},{}>".format(self.pk,self.dept_name)
__repr__ = __str__
'''
CREATE TABLE `dept_emp` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`id`),
KEY `emp_no` (`emp_no`),
KEY `dept_no` (`dept_no`),
CONSTRAINT `dept_emp_ibfk_1` FOREIGN KEY (`emp_no`) REFERENCES `employees` (`emp_no`) ON DELETE CASCADE,
CONSTRAINT `dept_emp_ibfk_2` FOREIGN KEY (`dept_no`) REFERENCES `departments` (`dept_no`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;
'''
class Dept_emp(models.Model):
emp_no = models.ForeignKey(employee, models.CASCADE,db_column='emp_no') # 外键,关联employee表的emp_no字段,级联删除,db_column 是数据库表的字段名
dept_no = models.ForeignKey(Department, models.CASCADE,db_column='dept_no') # 外键,关联Department表的dept_no字段,级联删除,db_column 是数据库表的字段名
from_date = models.DateField()
to_date = models.DateField()
class Meta:
db_table = 'dept_emp' # 数据表名
- 测试
# 项目目录 --> t1.py
import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'salary.settings')
django.setup(set_prefix=False) # 从wsgi.py 里找 --> get_wsgi_application --> django.setup(set_prefix=False)
'''以上属于固定写法,开始写自己的测试代码'''
from employee.models import employee,Salary,Department,Dept_emp
emgr = employee.objects
smgr = Salary.objects
demgr = Dept_emp.objects
# 查询10010员工的员工信息和部门编号
emp = emgr.get(pk=10010)
print(emp)
print(emp.dept_emp_set.all()) # 这里的dept_emp_set是一个Manager对象,all()返回的是一个查询集
# <QuerySet [<Dept_emp: Dept_emp object (10)>, <Dept_emp: Dept_emp object (11)>]>
for de in emp.dept_emp_set.all():
print(de.emp_no_id, de.dept_no.pk , de.dept_no.dept_name)
# (0.008) SELECT `employees`.`emp_no`, `employees`.`birth_date`, `employees`.`first_name`, `employees`.`last_name`, `employees`.`gender`, `employees`.`hire_date` FROM `employees` WHERE `employees`.`emp_no` = 10010 LIMIT 21; args=(10010,); alias=default
# <E 10010 [Piveteau Duangkaew]>
# (0.011) SELECT `dept_emp`.`id`, `dept_emp`.`emp_no`, `dept_emp`.`dept_no`, `dept_emp`.`from_date`, `dept_emp`.`to_date` FROM `dept_emp` WHERE `dept_emp`.`emp_no` = 10010 LIMIT 21; args=(10010,); alias=default
# <QuerySet [<Dept_emp: Dept_emp object (10)>, <Dept_emp: Dept_emp object (11)>]>
# (0.010) SELECT `dept_emp`.`id`, `dept_emp`.`emp_no`, `dept_emp`.`dept_no`, `dept_emp`.`from_date`, `dept_emp`.`to_date` FROM `dept_emp` WHERE `dept_emp`.`emp_no` = 10010; args=(10010,); alias=default
# (0.009) SELECT `departments`.`dept_no`, `departments`.`dept_name` FROM `departments` WHERE `departments`.`dept_no` = 'd004' LIMIT 21; args=('d004',); alias=default
# 10010 d004 Production
# (0.009) SELECT `departments`.`dept_no`, `departments`.`dept_name` FROM `departments` WHERE `departments`.`dept_no` = 'd006' LIMIT 21; args=('d006',); alias=default
# 10010 d006 Quality Management
- 通过第三张表建立关系
class Department(models.Model):
class Meta:
db_table = 'departments'
dept_no = models.CharField(max_length=4, primary_key=True)
dept_name = models.CharField(max_length=40,unique=True)
emps = models.ManyToManyField(employee,through='Dept_emp') # 多对多关系,通过Dept_emp表关联,emps是一个Manager对象,all()返回的是一个查询集
def __str__(self):
return "<D {},{}>".format(self.pk,self.dept_name)
__repr__ = __str__
Django迁移
# python manage.py makemigrations # 对有变化的才会生成迁移文件;
# python manage.py help migrate
# python manage.py migrate employee
Admin
# python manage.py createsuperuser
# 项目目录 employee admin.py 导入相关数据库映射的类,可以管理数据库
from .models import employee,Department
admin.site.register(employee)
admin.site.register(Department)
创建admin 用户并配置密码后,可以访问本地的http://localhost:8000/admin/ 登录
admin要使用,则必须要注册应用
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'employee',
]
路由
不同url交给同一个app(environ, start_response)
,app
函数内部对不同的请求(url)
做不同的处理。没同URL对应到app内部不同的函数
- 举例,简单的实现
# urls.py
# 不同path找到不同的视图函数handler,映射
router_map = {
'/index': h1,
'/test': h2,
}
# views.py
from urls.py import router_map
def app(env,sr): # 不同的python找到不同的handler,映射
x = router_map.get(request.path, handler_default)()
str('200 OK'), [(,)]
return x
根据WSGI原理,所有请求都交给一个应用程序处理。为了实现不同请求对应不同处理,最简单的方式是通过建立URL和处理函数之间的映射来实现路由。
路由的定义
路由就是根据访问的路径(Path)不同,调度不同的处理函数。可以使用模式匹配对路径进行处理。
Django 3.x 中的路由定义方式
在Django 3.x 中,使用 path
和 re_path
进行路由定义,与2.x略有区别。
主路由
主目录中的 urls.py
是路径匹配的入口,它定义在 settings.py
中的 ROOT_URLCONF = 'salary.urls'
。通常,主目录中的路由配置文件 urls.py
被称为主路由或一级路由。
- 路径转换器
str: 匹配任意非空字符串,但不能匹配路径分隔符
/
。这是默认的路径转换器。int: 匹配0或任意正整数,并将其转换为整数类型。
## 主路由文件在项目目录 --> salary --> urls.
from django.contrib import admin
from django.urls import path
# 只是用来测试的写在这里,第一参数必面是request,请求对象, environ已经被对象化了
from django.http import HttpResponse, HttpRequest
def path_test(request:HttpRequest, *args, **kwargs):
print('='* 30)
print(1, request, request.path ,request.path_info)
print(2,args)
print(3,kwargs)
print(4, *map(lambda x: (type(x),x) , kwargs.values()))
print('='* 30)
return HttpResponse(b'Test Page')
def test(request):
return HttpResponse(b'test2')
# 主路由, 一级路由, 根路由
urlpatterns = [
path('admin/', admin.site.urls),
# path('test/<course>/<year>',path_test), # path_test(request,**[course:python, year:abc])
# 1 <WSGIRequest: GET '/test/python/abc'> /test/python/abc /test/python/abc
# 2 ()
# 3 {'course': 'python', 'year': 'abc'}
path('test/<course>/<int:year>',path_test), # path_test(request,**[course:python, year:2022])') # str,int 是转换器,默认是str
# 1 <WSGIRequest: GET '/test/python/2021'> /test/python/2021 /test/python/2021
# 2 ()
# 3 {'course': 'python', 'year': 2021}
# 4 (<class 'str'>, 'python') (<class 'int'>, 2021)
path('test/', path_test),
path('', path_test)
# 以上执行顺序是,由上到下
]
URL路径 | URL模式 | 参数解析 |
---|---|---|
/test/python/2008 | test/\ |
[‘course’, \ |
[‘year’, \ |
||
/test/python/2008/ | test/\ |
[‘course’, \ |
[‘year’, \ |
从以上测试的结果上来看,采用的是关键字传参
URL | path模式 | 匹配结果 |
---|---|---|
/test/python/2008 | test/<course>/<year> | 匹配 |
/test/python/2008 | test/<course>/<year>/ | 301跳转到/test/python/2008/ |
/test/python/2008/ | test/<course>/<year> | 失败 |
/test/python/2008/ | test/<course>/<year>/ | 匹配 |
在定义 Django 中的路径模式时,建议使用以斜杠 /
结尾的形式,如 xxx/
。
这种形式的路径模式有助于保证 URL 的一致性和可读性,并且能够更好地与 Django 官方文档中的示例保持一致性。同时,也可以避免一些潜在的 URL 匹配问题。
对于需要更灵活的 URL 匹配需求,可以使用 re_path
,它支持正则表达式的方式定义路径模式。详情请参考Django官方文档。
二级路由
如果所有的路由都定义在主路由文件中,会导致主路由文件过于臃肿和混乱。为了解决这个问题,可以使用二级路由,将路由请求分发到应用的路由文件中。
添加应用路由文件
通常情况下,Django脚手架创建的应用目录中缺少 urls.py
文件,需要手动在应用目录中创建一个。这个文件负责定义应用内部的路由规则。
使用二级路由
在主路由文件中,通过配置路由模式将请求转发到应用的路由文件中,从而实现路由的分级管理。例如:
要在一级路由中定义二级路由文件
from django.contrib import admin
from django.urls import path,include
# 只是用来测试的写在这里,第一参数必面是request,请求对象, environ已经被对象化了
from django.http import HttpResponse, HttpRequest
urlpatterns = [
path('emp/', include('employee.urls')),
]
# 在项目目录 --> employee --> 创建 urls.py
from django.urls import path
from .views import index
urlpatterns = [
path('index/<int:id>',index), # 前缀/emp/, 二级路由:/emp/index
]
- 在view.py中定义视图
from django.shortcuts import render
from django.http import HttpRequest, HttpResponse
def index(request,id):
print('=*' * 30)
print(1, request, request.path)
print(2, type(id), id)
print('=*' * 30)
return HttpResponse('Use Template')
# curl http://localhost:8000/emp/index/1
Use Template%
Template
在Django中,模板用于生成HTML等内容,可以在视图中使用模板引擎渲染数据。模板引擎会根据配置查找模板文件并渲染页面。
配置模板目录
在主配置文件 settings.py
中,可以配置模板引擎的相关设置,包括模板目录的搜索路径等。主要配置项包括:
DIRS
: 模板目录列表,表示模板引擎在哪些目录中搜索模板文件。通常包括项目根目录下的templates
目录以及其他公共模板目录。APP_DIRS
: 布尔值,指定是否在应用目录中搜索模板。如果设置为True
,则模板引擎会在每个应用的templates
目录中搜索模板文件。
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [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',
],
},
},
]
- 在项目根目下新建对应的目录
templates
,index.html
from django.shortcuts import render
from django.http import HttpRequest, HttpResponse
from django.template.loader import get_template
from django.template.backends.django import Template
from datetime import datetime
def index(request,id):
# print('=*' * 30)
# print(1, request, request.path)
# print(2, type(id), id)
# print('=*' * 30)
# t:Template = get_template('index.html') # 找到文件并open read 内容,字符串
# print(type(t),t)
# print(t.template,t.origin)
#x = HttpResponse(t.reader({'test':"replace"},request)) # 利用数据替换占位符, 封装成Response对象
mydit = {
'a':100,
'b': 0,
'c': list(range(1,100)),
'date': datetime.now
}
return render(request, 'index.html',{
'test':30000,
'mydata': mydit
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> Test Page! </title>
</head>
<body>
<!-- This is Template {{ test }}
<br>
{{ mydata }}
<h1> {{ mydata.a }} {{ mydata.c}} </h1>
<h1> {{mydata.c.1 }} </h1>
<h1> {{mydata.keys }} </h1>
<h1> {{mydata.values }} </h1>
<br>
<br>
{% for key, value in mydata.items %}
{% if key == 'c' %}
{% for i in value %}
{{ i }}
{% endfor %}
{% endif %}
{% endfor %} -->
<table border="1" width="100%">
{% for c in mydata.d %}
{% if forloop.first %}
序号 ~
说明 ~
说明
{% endif %}
{{ forloop.counter }}
{{ c }}
{{ c }} is xxx
{% if forloop.last %}
分页
{% endif %}
{% endfor %}
</body>
</html>
过滤器 | 说明 | 举例 |
---|---|---|
cut | 切掉字符串中的指定字符 | {{ value \| cut:'b' }} |
lower | 转换为小写 | {{ text \| lower }} |
upper | 转换为大写 | {{ text \| upper }} |
truncatewords | 保留指定个数的单词 | {{ bio \| truncatewords:'30' }} |
join | 对序列拼接 | {{ d.e \| join:'//' }} |
first | 取序列第一个元素 | {{ mylist \| first }} |
last | 取序列最后元素 | {{ mylist \| last }} |
add | 加法。参数是负数就是减法 | 数字加{{ value \| add:'100'}} 列表合并{{mylist \| add:newlist}} |
addslashes | 在反斜杠、单引号或者双引号前面加上反斜杠 | {{ text \| addslashes }} |
length | 返回变量的长度 | {{ value \| length }} |
default | 变量等价False则使用缺省值 | {{ value \| default:'nothing' }} |
yesno | 返回3个值中的一个 | {{ value \| yesno:'yeah,no,maybe' }} |
divisibleby | 能否被整除 | {{ value \| divisibleby:'3' }} |
default_if_none | 变量为None使用缺省值 | {{ value \| default_if_none:'nothing' }} |
date | 格式化 date 或者 datetime 对象 | {{ value \| date:'Y-m-d H:i:s' }} |