自强学堂Django教程
目录
一、Django的MTV模式
二、Django基本命令
2.1 安装Django
2.2 创建一个django项目
2.3 创建一个应用
2.4 启动Django项目
2.5 同步更改数据库表或字段
2.6 清空数据库
2.7 创建超级管理员
2.8 导入导出数据
2.9 Django项目环境终端
2.10 数据库命令行
2.11 查看所有命令
三、 静态文件配置
3.1 配置方法一
3.2 配置方法二
四、第一个Django应用
4.1 新建一个名叫mysite的项目
4.2 新建一个名叫learn的应用
4.3 定义视图函数views.py
4.4 定义网址与视图函数对应关系
五、控制器urls.py
5.1 url()语法解析
5.2 无名分组
5.3 有名分组(named group)
5.4 引用每个应用自己的urls.py
5.5 URL name详解
六、视图函数views.py
6.1 一个简单的视图函数
6.2 HttpRequest对象
6.3 render函数
6.4 redirect函数
七、模板(templates)
7.1 变量引用
7.2 模板之过滤器
default
length
filesizeformat
date
slice
truncatechars
safe
7.3 模板之标签
for标签
for … empty
if 标签
with
csrf_token
八、Django-model基础
8.1 ORM 映射关系
8.2 创建表
8.3 同步数据库
8.4 插入数据
新建一个对象的4种方式
8.5 查询数据
Django是目前最流行的Python Web框架。
一、Django的MTV模式
Django的MTV模式本质是各组件之间为了保持松耦合关系,MTV分别代表:
- Model(模型):负责业务对象与数据库的对象(ORM)
- Template(模版):负责如何把页面展示给用户
- View(视图):负责业务逻辑,并在适当的时候调用Model和Template。
注意:此外,Django还有一个url分发器,它的作用是将一个个URL的页面请求分发给不同的view视图函数处理,view再调用相应的Model和Template,然后返回给用户。
Django处理用户访问请求的流程
- 根据用户访问的URL,通过urls.py中的urlpatterns对访问路径进行正则匹配,然后交给对应视图函数(views.py中定义的函数)去处理;
- views.py视图函数接收一下参数是request请求对象,对用户请求做相应的逻辑处理。
- 逻辑处理过程中,如果需要存取数据,则要调用Model模块去操作数据库,然后将数据返回给视图函数;
- 视图函数将取回的数据,通过
render()
方法渲染到Template模版文件(即html文件)中,并返回给用户。
二、Django基本命令
2.1 安装Django
pip3 install django
2.2 创建一个django项目
django-admin.py startproject mysite
//或
python manage.py startproject mysite
//mysite为自定义的项目名称
执行上述命令,会在当前目录下生成一个名叫mysite的工程,目录结构如下:
- manage.py ----- Django项目里面的工具,通过它可以调用django shell和数据库等。
- settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。
- urls.py ----- 负责把URL模式映射到应用程序的视图函数。
2.3 创建一个应用
进入到mysite项目目录下
python manage.py startapp blog
//blog为自定义的应用程序名称
目录结构如下;
2.4 启动Django项目
python manage.py runserver [IP:PORT]
//如果不加IP和端口,则会默认开启本机的8000端口;
2.5 同步更改数据库表或字段
Django 1.7.1及以上的版本用以下命令
# 1. 创建更改的文件
python manage.py makemigrations
# 2. 将生成的py文件应用到数据库
python manage.py migrate
旧版本的Django 1.6及以下用
python manage.py syncdb
2.6 清空数据库
python manage.py flush
此命令会询问是 yes 还是 no, 选择 yes 会把数据全部清空掉,只留下空表。
2.7 创建超级管理员
python manage.py createsuperuser
#按照提示输入用户名和对应的密码就好了,邮箱可以留空,用户名和密码必填
#修改用户密码可以用:
python manage.py changepassword username
2.8 导入导出数据
# 导出
python manage.py dumpdata appname > appname.json
# 导入
python manage.py loaddate appname.json
2.9 Django项目环境终端
python manage.py shell
这个命令和 直接运行 python 进入 shell 的区别是:你可以在这个 shell 里面调用当前项目的 models.py 中的 API,对于操作数据,还有一些小测试非常方便。
2.10 数据库命令行
python manage.py dbshell
Django 会自动进入在settings.py中设置的数据库,如果是 MySQL 或 postgreSQL,会要求输入数据库用户密码。在这个终端可以执行数据库的SQL语句。
2.11 查看所有命令
python manage.py
查看所有的命令,忘记子名称的时候特别有用。
三、 静态文件配置
Django本身不处理静态文件,静态文件交由Web服务器处理,以Nginx为例,简单的处理逻辑如下:
概述:
URL请求 ---> 按nginx.conf中的location配置的规则先处理 --->
|---> 如果是静态文件,则直接由nginx处理;
|---> 如果不是,则交由Django处理,Django根据urls.py中的规则进行匹配。
以上是部署到Web服务器后的处理方式。为了便于开发,Django提供了在开发环境中对静态文件的处理机制,方法如下(static配置):
静态文件(static)主要指css、js、image这样的文件。
3.1 配置方法一
静态文件配置参考
在settings.py中编辑如下:
STATIC_URL = '/static/' # 引用名
STATICFILES_DIRS = (os.path.join(BASE_DIR,"statics"),) #实际名 ,即实际文件夹的名字
注意: 1、 django对引用名和实际名进行映射,引用静态文件时,只能按照引用名找,不能按实际名去找。
//不正确,不能直接用statics去找,必须用STATIC_URL = '/static/' //正确
2、
STATICFILES_DIRS = (("app01",os.path.join(BASE_DIR, "app01/statics")),) //正确
3.2 配置方法二
- 首先确保
settings.py
的INSTALLED_APPS
列表中包含django.contrib.staticfiles
; - 在你的
settings.py
文件中,定义STATIC_URL
,例如:STATIC_URL = '/static/'
- 在模版文件中这样引用:
{% load static %} //写在文件第一行
- 将您的静态文件存储在应用程序中名为static的文件夹中。 例如:my_app/static/my_app/example.jpg。
四、第一个Django应用
4.1 新建一个名叫mysite的项目
django-admin startproject mysite
4.2 新建一个名叫learn的应用
python manage.py startapp learn # learn 是一个app的名称
把新建的app名称加入settings.py中的INSTALL_APPS中;
修改mysite/mysite/settings.py
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'learn',
)
注意:新建的 app 如果不加到 INSTALL_APPS 中的话, django 就不能自动找到app中的模板文件(app-name/templates/下的文件)和静态文件(app-name/static/中的文件)
4.3 定义视图函数views.py
视图函数是对用户的访问请求进行逻辑处理,然后再返回给浏览器
编辑mysite/learn/views.py
:
from django.http import render,HttpResponse
def index(request):
return HttpResponse(u"欢迎光临 !")
注意:定义了一个index()函数,第一个参数必须是request,与网页发来的请求有关,request 变量里面包含GET或POST的内容,用户浏览器,系统等信息在里面。
函数返回一个HttpResponse 对象,是用来向网页返回内容的。
那么如何让网址和视图函数关联起来呢?
4.4 定义网址与视图函数对应关系
也就是定义一个网址,应该用哪个视图函数去处理并响应。
编辑mysite/mysite/urls.py
from django.conf.urls import url
from django.contrib import admin
from learn import views as learn_views # new
urlpatterns = [
url(r'^$', learn_views.index), # new
url(r'^index/', learn_views.index), # new
url(r'^admin/', admin.site.urls),
]
以上修改并保存后,运行项目,看一下效果!
$ python manage.py runserver
Performing system checks...
System check identified no issues (0 silenced).
You have unapplied migrations; your app may not work properly until they are applied.
Run 'python manage.py migrate' to apply them.
December 22, 2015 - 11:57:33
Django version 1.9, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
打开浏览器,访问http://127.0.0.1:8000/ 或http://127.0.0.1:8000/index/
会在页面上看到 “欢迎光临!”
五、控制器urls.py
5.1 url()语法解析
urlpatterns = [
url(正则表达式, views视图函数,参数,别名),
]
参数说明:
1. 一个正则表达式字符串
2. 一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
3. 可选的要传递给视图函数的默认参数(字典形式),一般不用
4. 一个可选的name参数,是为视图函数起的别名,在模板文件中引用时用到。
5.2 无名分组
如果URL中带有需要传给后端服务器处理的值,就可以在url()
中将匹配此值的正则放在括号()中即可,然后django会自动将括号()中的正则匹配到的值当作参数传给后面的视图函数。视图函数在定义时,必须要定义接收参数的形参,否则会报错。
编辑urls.py
,添加如下配置
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/([0-9]{4})/$', views.year_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]
- 访问 http://127.0.0.1:8000/articles/2012 ,会被上述代码中第2条url()中的正则匹配到,并且会将([0-9]{4})匹配到的值2012当作参数传给对应的视图函数,所以会调用
views.year_archive(request,'2012')
,在views.py中定义函数year_archive()时,一定要多加一个形参用来接收url中传递的参数,例:
def year_archive(request,number):
return HttpResponse(number)
- 访问 http://127.0.0.1:8000/articles/2012/12/ , 会被 上述代码中第3条url()中的正则匹配到,并且会将 ([0-9]{4}) 和 ([0-9]{2})匹配到的值2012和12当作参数传给对应的视图函数,调用
views.month_archive(request,'2012','12')
,视图函数定义应该是这样:
def month_archive(request,num1,num2):
return HttpResponse(num1,num2)
5.3 有名分组(named group)
有名分组的语法:(?P
其中name是自定义的组名称,pattern是要匹配的模式。
有名分组会将name当作Key,pattern匹配到的值当作Value,以关键字传参给视图函数,定义视图函数时,定义的形参,必须与name同名。
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/(?P[0-9]{4})/$', views.year_archive),
url(r'^articles/(?P[0-9]{4})/(?P[0-9]{2})/$', views.month_archive),
]
- 访问 http://127.0.0.1:8000/articles/2012,会被上述第2条url()匹配到,请求将调用
views.year_archive(request,year='2012')
视图函数。视图函数定义时,应该是这样:
def year_archive(request,year):
return HttpResponse(year)
- 访问 http://127.0.0.1:8000/articles/2012/12/ , 会被 上述代码中第3条url()中的正则匹配到,请求将调用
views.month_archive(request,year='2012',month='12')
视图函数。视图函数定义时,应该是这样:
def month_archive(request,year,month):
return HttpResponse(year,month)
5.4 引用每个应用自己的urls.py
当一个网站有太多的url时,所有的url都通过全局urls.py去映射视图函数,会显得非常凌乱。这时将每个应用的url通过应用自己的urls.py去映射视图函数,结构就会清晰很多。
新建 blog/urls.py
# 需要先引入include
from django.conf.urls import include, url
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^blog/', include('blog.urls')),
] # 将所有以blog开头的URL交给blog应用下面的urls.py处理
5.5 URL name详解
url()
中name参数详解
六、视图函数views.py
一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是任何东西都可以。无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你的Python目录下面。除此之外没有更多的要求了——可以说“没有什么神奇的地方”。为了将代码放在某处,约定是将视图放置在项目或应用程序目录中的名为views.py的文件中。
6.1 一个简单的视图函数
下面是一个返回当前日期和时间作为HTML文档的视图:
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
html = "It is now %s." % now
return HttpResponse(html)
让我们逐行阅读上面的代码:
- 首先,我们从 django.http模块导入了HttpResponse类,以及Python的datetime库。
接着,我们定义了current_datetime函数。它就是视图函数。每个视图函数都使用HttpRequest对象作为第一个参数,并且通常称之为request。
注意,视图函数的名称并不重要;不需要用一个统一的命名方式来命名,以便让Django识别它。我们将其命名为current_datetime,是因为这个名称能够精确地反映出它的功能。
这个视图会返回一个HttpResponse对象,其中包含生成的响应。每个视图函数都负责返回一个HttpResponse对象。
6.2 HttpRequest对象
视图函数的第一个参数就是HttpRequest对象,通常定为request,这个对象中封装了与请求相关的一些属性和方法,如下:
属性:
from django.shortcuts import render
def index(request):
request.path #请求页面的全路径,不包括域名
request.method #HTTP请求访求,大写的字符串,如GET/POST
request.GET #包含所有HTTP GET请求方法获取的参数,字典
request.POST #包含所有HTTP POST请求方法获取的参数,字典
request.COOKIES #包含所有cookies的标准python字典对象,keys和values都是字符串
request.FILES #包含所有上传文件的类字典对象,FILES中的每一个Key都是标签中name属性的值,FILES中的每一个value同时也是一个标准的python字典对象,包含下面三个keys:
//filename: 上传文件的文件名,用字符串表示
//content_type: 上传文件的Content Type
//content: 上传文件的原始内容
request.user #是一个django.contrib.auth.models.User对象,代表当前登陆的用户。如果访问用户当前没有登陆,user将被初始化为django.contrib.auth.models.AnonymousUser的实例。你可以通过user的is_authenticated()方法来辨别用户是否登陆:if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware时该属性才可用
request.session #唯一可读写的属性,代表当前会话的字典对象;自己有激活Django中的session支持时该属性才可用。
方法:
def index(request):
request.get_full_path() #请求全路径,包含参数
注意:当键值对的值有多个的时候,比如:type='checkbox'类型的input标签、select标签,就需要用如下方法:
request.POST.getlist('hobby')
6.3 render函数
render()
函数的功能:将python中的变量,嵌入到模板文件(html文件)中,将渲染后的html文件返回给用户。
语法:render(request,template_name[,context])
参数:
- request:请求对象
- template_name:要使用的模板文件名
- context:是一个字典,key将在模板中被引用,value是当前视图函数中的某一个变量。可以直接用
locals()
函数代替,locals()
会将当前函数中的所有变量提供给模板使用,模板在使用时,直接写{{ 变量名 }}
即可引用该变量。
示例:
from django.shortcuts import render
import datetime
#视图函数
def index(request):
now = datetime.datetime.now()
return render(request,'index.html',{'current_time':now})
#也可以这样:
#
在templates目录中创建一个模板文件index.html,内容如下:
{{ current_time }}
这样既可将视图中的变量渲染到html文件中。
使用locals()
:
from django.shortcuts import render
import datetime
#视图函数
def index(request):
now = datetime.datetime.now()
return render(request,'index.html',locals())
模板文件中就可以直接引用变量了:
{{ now }}
6.4 redirect函数
重定向到一个新页面
#视图函数
def addBook(request):
if request.method == 'POST':
...
此段代码是向数据库写入前端页面提交的数据
...
return redirect('/index/') #数据写入完成后,重新回到首页
return render(request,'addbook.html')
注意:默认情况下,
redirect()
返回一个临时重定向,如果需要永久重定向,则需要设置permanent参数为True,如下:def myView(req): return redirect('/index/',permanent=Ture)
也可以是一个完整的URL
def my_view(request):
...
return redirect('http://example.com/')
七、模板(templates)
Django的模板:HTML代码 + 逻辑控制代码
7.1 变量引用
在模板中引用视图函数中的变量,需要通过双大括号将变量包括其中。
语法格式:{{ 变量名 }}
views.py
def index(request):
import datetime
s="hello"
l=[111,222,333] # 列表
dic={"name":"yuan","age":18} # 字典
date = datetime.date(1993, 5, 2) # 日期对象
class Person(object):
def __init__(self,name):
self.name=name
person_yuan=Person("yuan") # 自定义类对象
person_egon=Person("egon")
person_alex=Person("alex")
person_list=[person_yuan,person_egon,person_alex]
return render(request,"index.html",{"l":l,"dic":dic,"date":date,"person_list":person_list})
template中的index.html内容如下:
列表:{{ l.0 }}
列表:{{ l.2 }}
字典:{{ dic.name }}
日期:{{ date.year }}
类对象列表:{{ person_list.0.name }}
urls.py内容如下:
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
]
运行项目:python manage.py runserver 9000
浏览器访问http://127.0.0.1:9000/index/,会得到如下图结果:
注意:句点符也可以用来引用对象的方法(无参数方法)。
字典:{{ dic.name.upper }}
7.2 模板之过滤器
语法:{{obj|filter__name:param}}
default
如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值。例如:
{{ value|default:"nothing" }}
length
返回值的长度。它对字符串和列表都起作用。例如:
{{ value|length }}
//如果 value 是 ['a', 'b', 'c', 'd'],那么输出是 4。
filesizeformat
将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。例如:
{{ value|filesizeformat }}
//如果 value 是 123456789,输出将会是 117.7 MB。
date
如果 value=datetime.datetime.now()
{{ value|date:"Y-m-d" }}
//输出的日期格式为xxxx-xx-xx 年-月-日
slice
对字符串或列表进行切片,如果 value="hello world"
{{ value|slice:"2:-1" }}
//输出 ‘llo worl’
truncatechars
如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。
参数:要截断的字符数
例如:
{{ value|truncatechars:9 }}
truncatewords是截断指定的单词个数
safe
Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。比如:
value="点击"
{{ value|safe}}
//可以将value在页面上渲染成一个a标签,如果不用safe过滤器,则只是显示value值的字符串
7.3 模板之标签
标签看起来像是这样的: {% tag %}。标签比变量更加复杂:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。
一些标签需要开始和结束标签 (例如{% tag %} ...标签 内容 ... {% endtag %})。
for标签
遍历每一个元素
{% for person in person_list %}
{{ person.name }}
{% endfor %}
可以利用
{% for obj in list reversed %}
反向完成循环。
遍历一个字典:
{% for key,val in dic.items %}
{{ key }}:{{ val }}
{% endfor %}
注意:循环序号可以通过
{{ forloop }}
显示.forloop.counter //显示循环序号,从1开始 forloop.counter0 //显示循环序号,从0开始 forloop.revcounter //反向显示循环序号,从大到小,最后一位是1 forloop.revcounter0 //从大到小,最后一位是0 forloop.first //第一个是True,后面的都是False forloop.last //最后一个是True,前面的都是False
for ... empty
for 标签带有一个可选的{% empty %}
从句,以便在给出的组是空的或者没有被找到时,可以另做其它操作。
{% for person in person_list %}
{{ person.name }}
{% empty %}
sorry,no person here
{% endfor %}
if 标签
{% if %}
会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。
{% if num > 100 or num < 0 %}
无效
{% elif num > 80 and num < 100 %}
优秀
{% else %}
凑活吧
{% endif %}
with
使用一个简单地名字缓存一个复杂的变量,当你需要使用一个“昂贵的”方法(比如访问数据库)很多次的时候是非常有用的。
{% with total=business.employees.count %}
{{ total }} employee{{ total|pluralize }}
{% endwith %}
csrf_token
这个标签用于跨站请求伪造保护,一般用在表单的请求方法是POST时,将
{% csrf_token %}
放在表单中
{% csrf_token %}
八、Django-model基础
Django 模型是与数据库相关的,与数据库相关的代码一般写在 models.py 中,Django 支持 sqlite3, MySQL, PostgreSQL等数据库,只需要在settings.py中配置即可,不用更改models.py中的代码,丰富的API极大的方便了使用。
8.1 ORM 映射关系
表名 -----------> 类名
字段 -----------> 属性
表记录 --------> 类实例化的对象
8.2 创建表
编辑app_name/models.py
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
我们新建了一个Person类,继承自models.Model, 一个人有姓名和年龄。
这里用到了两种Field,更多Field类型,请参考此篇文档
在settings.py中添加LOGGING,可以查看数据库操作时对应的SQL语句:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
8.3 同步数据库
# 先 cd 进入 manage.py 所在的那个文件夹下,输入下面的命令
# Django 1.7 及以上的版本需要用以下命令
python manage.py makemigrations
python manage.py migrate
命令执行,会看到下图:
我们会看到,Django生成了一系列的表,也生成了我们新建的people_person这个表。
8.4 插入数据
也就是新建一个对象,每行表记录就是一个对象
$ python manage.py shell
>>> from app_name.models import Person
>>> Person.objects.create(name="WeizhongTu", age=24)
>>>
我们新建了一个用户WeizhongTu 那么如何从数据库是查询到它呢?
>>> Person.objects.get(name="WeizhongTu")
>>>
我们用了一个 .objects.get() 方法查询出来符合条件的对象,但是大家注意到了没有,查询结果中显示
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
def __str__(self):
return self.name
按 CTRL + C 退出当前的 Python shell, 重复上面的操作,我们就可以看到:
>>>from app_name import Person Person.objects.get(name="WeizhongTu")
>>>
新建一个对象的4种方式
第一种:
Person.objects.create(name=name,age=age)
第二种:
p = Person(name="WZ", age=23)
p.save()
第三种:
p = Person(name="TWZ")
p.age = 23
p.save()
第四种:
Person.objects.get_or_create(name="WZT", age=23)
这种方法是防止重复很好的方法,但是速度要相对慢些,返回一个元组,第一个为Person对象,第二个为True或False, 新建时返回的是True, 已经存在时返回False.
8.5 查询数据
也就是获取表记录(对象)
Person.objects.all()
Person.objects.all()[:10] 切片操作,获取10个人,不支持负索引,切片可以节约内存
Person.objects.get(name=name)
#get是用来获取一个对象的,如果需要获取满足条件的一些人,就要用到filter
Person.objects.filter(name="abc") # 等于Person.objects.filter(name__exact="abc") 名称严格等于 "abc" 的人
Person.objects.filter(name__iexact="abc") # 名称为 abc 但是不区分大小写,可以找到 ABC, Abc, aBC,这些都符合条件
Person.objects.filter(name__contains="abc") # 名称中包含 "abc"的人
Person.objects.filter(name__icontains="abc") #名称中包含 "abc",且abc不区分大小写
Person.objects.filter(name__regex="^abc") # 正则表达式查询
Person.objects.filter(name__iregex="^abc") # 正则表达式不区分大小写
#filter是找出满足条件的,当然也有排除符合某条件的
Person.objects.exclude(name__contains="WZ") # 排除包含 WZ 的Person对象
Person.objects.filter(name__contains="abc").exclude(age=23) # 找出名称含有abc, 但是排除年龄是23岁的