抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

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 中,使用 pathre_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>/ [‘course’, \<class ‘str’>, ‘python’]
[‘year’, \<class ‘str’>, ‘2008’]
/test/python/2008/ test/\str:course\/\int:year\/ [‘course’, \<class ‘str’>, ‘python’]
[‘year’, \<class ‘int’>, 2008]

从以上测试的结果上来看,采用的是关键字传参

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' }}

    评论