1. MVT 模式
有一种程序设计模式叫MVC,其核心思想是分工、解耦,让不同的代码块之间降低耦合,增强代码的可扩展性和可移植性,实现向后兼容。
M全拼为Model,主要封装对数据库层的访问,对数据库中的数据进行增、删、改、查操作。
V全拼为View,用于封装结果,生成页面展示的html内容。
C全拼为Controller,用于接收请求,处理业务逻辑,与Model和View交互,返回结果。
M全拼为Model,与MVC中的M功能相同,负责和数据库交互,进行数据处理。
V全拼为View,与MVC中的C功能相同,接收请求,进行业务处理,返回应答。
T全拼为Template,与MVC中的V功能相同,负责封装构造要返回的html。
2. 创建
django-admin startproject 工程名称
python manage.py startapp 应用名称
python manage.py runserver ip:port
注册 app
3. 视图
from django.http import HttpResponse
def index(request):
"""
index视图
:param request: 包含了请求信息的请求对象
:return: 响应对象
"""
return HttpResponse("hello the world!")
说明:
- 视图函数的第一个传入参数必须定义,用于接收Django构造的包含了请求数据的HttpReqeust对象,通常名为request。
- 视图函数的返回值必须为一个响应对象,不能像Flask一样直接返回一个字符串,可以将要返回的字符串数据放到一个HTTPResponse对象中。
4. 路径url
from django.conf.urls import url
from . import views
# urlpatterns是被django自动识别的路由列表变量
urlpatterns = [
# 每个路由信息都需要使用url函数来构造
# url(路径, 视图)
url(r'^index/$', views.index),
]
总路由中:
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns= [
url(r'^admin/', admin.site.urls), # django默认包含的
# 添加
url(r'^users/', include('users.urls')),
]
5. 配置
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
静态文件:
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static_files'),
]
Django 仅在调试模式下(DEBUG=True)能对外提供静态文件。
当DEBUG=False工作在生产模式时,Django不再对外提供静态文件,需要是用collectstatic命令来收集静态文件并交由其他静态文件服务器来提供。
app 应用配置
from django.apps import AppConfig
class UsersConfig(AppConfig):
name = 'users'
verbose_name = '用户管理'
6. 请求
HttpRequest对象的属性GET、POST都是QueryDict类型的对象.
# /qs/?a=1&b=2&a=3
def qs(request):
a = request.GET.get('a')
b = request.GET.get('b')
alist = request.GET.getlist('a')
print(a) # 3
print(b) # 2
print(alist) # ['1', '3']
return HttpResponse('OK')
重要:查询字符串不区分请求方式,即假使客户端进行POST方式的请求,依然可以通过request.GET获取请求中的查询字符串数据。
7. 请求体
请求体数据格式不固定,可以是表单类型字符串,可以是JSON字符串,可以是XML字符串,应区别对待。
可以发送请求体数据的请求方式有POST、PUT、PATCH、DELETE。
表单类型 Form Data
前端发送的表单类型的请求体数据,可以通过request.POST属性获取,返回QueryDict对象。
def get_body(request):
a = request.POST.get('a')
b = request.POST.get('b')
alist = request.POST.getlist('a')
print(a)
print(b)
print(alist)
return HttpResponse('OK')
重要:只要请求体的数据是表单类型,无论是哪种请求方式(POST、PUT、PATCH、DELETE),都是使用request.POST来获取请求体的表单数据。
非表单类型 Non-Form Data
非表单类型的请求体数据,Django无法自动解析,可以通过request.body属性获取最原始的请求体数据,自己按照请求体格式(JSON、XML等)进行解析。request.body返回bytes类型。
# {"a": 1, "b": 2}
import json
def get_body_json(request):
json_str = request.body
json_str = json_str.decode() # python3.6 无需执行此步
req_data = json.loads(json_str)
print(req_data['a'])
print(req_data['b'])
return HttpResponse('OK')
8. 请求头
可以通过request.META属性获取请求头headers中的数据,request.META为字典类型。
常见的请求头如:
CONTENT_LENGTH – The length of the request body (as a string).
CONTENT_TYPE – The MIME type of the request body.
HTTP_ACCEPT – Acceptable content types for the response.
HTTP_ACCEPT_ENCODING – Acceptable encodings for the response.
HTTP_ACCEPT_LANGUAGE – Acceptable languages for the response.
HTTP_HOST – The HTTP Host header sent by the client.
HTTP_REFERER – The referring page, if any.
HTTP_USER_AGENT – The client’s user-agent string.
QUERY_STRING – The query string, as a single (unparsed) string.
REMOTE_ADDR – The IP address of the client.
REMOTE_HOST – The hostname of the client.
REMOTE_USER – The user authenticated by the Web server, if any.
REQUEST_METHOD – A string such as "GET" or "POST".
SERVER_NAME – The hostname of the server.
SERVER_PORT – The port of the server (as a string).
def get_headers(request):
print(request.META['CONTENT_TYPE'])
return HttpResponse('OK')
其他常用HttpRequest对象属性
method:一个字符串,表示请求使用的HTTP方法,常用值包括:'GET'、'POST'。
user:请求的用户对象。
path:一个字符串,表示请求的页面的完整路径,不包含域名和参数部分。
encoding:一个字符串,表示提交的数据的编码方式。
如果为None则表示使用浏览器的默认设置,一般为utf-8。
这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值。
FILES:一个类似于字典的对象,包含所有的上传文件。
9.响应
视图在接收请求并处理后,必须返回HttpResponse对象或子对象。HttpRequest对象由Django创建,HttpResponse对象由开发人员创建。
HttpResponse
可以使用django.http.HttpResponse来构造响应对象。
HttpResponse(content=响应体, content_type=响应体数据类型, status=状态码)
也可通过HttpResponse对象属性来设置响应体、响应体数据类型、状态码:
content:表示返回的内容。
status_code:返回的HTTP响应状态码。
content_type:指定返回数据的的MIME类型。
from django.http import HttpResponse
def demo_view(request):
return HttpResponse('itcast python', status=400)
或者
response = HttpResponse('itcast python')
response.status_code = 400
response['Itcast'] = 'Python'
return response
JsonResponse
from django.http import JsonResponse
def demo_view(request):
return JsonResponse({'city': 'beijing', 'subject': 'python'})
redirect 重定向
from django.shortcuts import redirect
def demo_view(request):
return redirect('/index.html')
10. Cookie
特点:
Cookie以键值对的格式进行信息的存储。
Cookie基于域名安全,不同域名的Cookie是不能互相访问的,如访问google.com时向浏览器中写了Cookie信息,使用同一浏览器访问baidu.com时,无法访问到google.com写的Cookie信息。
当浏览器请求某网站时,会将浏览器存储的跟网站相关的所有Cookie信息提交给网站服务器。
设置 Cookie
可以通过HttpResponse对象中的set_cookie方法来设置cookie。
HttpResponse.set_cookie(cookie名, value=cookie值, max_age=cookie有效期)``
def demo_view(request):
response = HttpResponse('ok')
response.set_cookie('itcast1', 'python1') # 临时cookie
response.set_cookie('itcast2', 'python2', max_age=3600) # 有效期一小时
return response
读取 Cookie
可以通过HttpRequest对象的COOKIES属性来读取本次请求携带的cookie值。request.COOKIES为字典类型。
def demo_view(request):
cookie1 = request.COOKIES.get('itcast1')
print(cookie1)
return HttpResponse('OK')
11. Session
启用Session
Django项目默认启用Session。
储存方式
在settings.py文件中,可以设置session数据的存储方式,可以保存在数据库、本地缓存等。
- Redis
在redis中保存session,需要引入第三方扩展,我们可以使用django-redis来解决。
pip install django-redis
# settings.py
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
注意
如果redis的ip地址不是本地回环127.0.0.1,而是其他地址,访问Django时,可能出现Redis连接错误,如下:
解决方法:
修改redis的配置文件,添加特定ip地址。
打开redis的配置文件
sudo vim /etc/redis/redis.conf
在如下配置项进行修改(如要添加10.211.55.5地址)
重新启动redis服务
sudo service redis-server restart
Session 操作
通过HttpRequest对象的session属性进行会话的读写操作。
request.session['键']=值
request.session.get('键',默认值)
request.session.clear()
request.session.flush()
del request.session['键']
request.session.set_expiry(value)
如果value是一个整数,session将在value秒没有活动后过期。
如果value为0,那么用户session的Cookie将在用户的浏览器关闭时过期。
如果value为None,那么session有效期将采用系统默认值,默认为两周,可以通过在settings.py中设置SESSION_COOKIE_AGE来设置全局默认值。
12. 类视图
# 以函数的方式定义的视图称为函数视图,函数视图便于理解。但是代码可读性与复用性都不佳。
def register(request):
"""处理注册"""
# 获取请求方法,判断是GET/POST请求
if request.method == 'GET':
# 处理GET请求,返回注册页面
return render(request, 'register.html')
else:
# 处理POST请求,实现注册逻辑
return HttpResponse('这里实现注册逻辑')
在Django中也可以使用类来定义一个视图,称为类视图。
使用类视图可以将视图对应的不同请求方式以类中的不同方法来区别定义。如下所示
from django.views.generic import View
class RegisterView(View):
"""类视图:处理注册"""
def get(self, request):
"""处理GET请求,返回注册页面"""
return render(request, 'register.html')
def post(self, request):
"""处理POST请求,实现注册逻辑"""
return HttpResponse('这里实现注册逻辑')
类视图的好处:
- 代码可读性好
- 类视图相对于函数视图有更高的复用性, 如果其他地方需要用到某个类视图的某个特定逻辑,直接继承该类视图即可
类视图的使用
定义类视图需要继承自Django提供的父类View,可使用from django.views.generic import View或者from django.views.generic.base import View 导入.
配置路由时,使用类视图的as_view()方法来添加。
from django.utils.decorators import method_decorator
urlpatterns = [
# 视图函数:注册
# url(r'^register/$', views.register, name='register'),
# 类视图:注册
url(r'^register/$', views.RegisterView.as_view(), name='register'),
]
类视图的原理
as_view 中实现了不同请求的分发.
源码略.
类视图使用装饰器
def my_decorator(func):
def wrapper(request, *args, **kwargs):
print('自定义装饰器被调用了')
print('请求路径%s' % request.path)
return func(request, *args, **kwargs)
return wrapper
# 为全部请求方法添加装饰器
@method_decorator(my_decorator, name='dispatch')
class DemoView(View):
def get(self, request):
print('get方法')
return HttpResponse('ok')
def post(self, request):
print('post方法')
return HttpResponse('ok')
# 为特定请求方法添加装饰器
@method_decorator(my_decorator, name='get')
class DemoView(View):
def get(self, request):
print('get方法')
return HttpResponse('ok')
def post(self, request):
print('post方法')
return HttpResponse('ok')
为什么需要使用method_decorator???
- 为函数视图准备的装饰器,其被调用时,第一个参数用于接收request对象.
- 而类视图中请求方法被调用时,传入的第一个参数不是request对象,而是self 视图对象本身,第二个位置参数才是request对象.
- 所以如果直接将用于函数视图的装饰器装饰类视图方法,会导致参数传递出现问题。
- method_decorator的作用是为函数视图装饰器补充第一个self参数,以适配类视图方法。
构造Mixin扩展类
定义扩展类
class BaseView(object):
@classmethod
def as_view(cls, *args, **kwargs):
print('在最终as_view方法执行之前别调用')
view = super().as_view(*args, **kwargs)
view = my_decorator(view)
return view
使用扩展类
class DemoView(BaseView, View):
def get(self, request):
return HttpResponse('get page')
def post(self, request):
return HttpResponse('post page')
13. 中间件
Django中的中间件是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出。中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性。
我们可以使用中间件,在Django处理视图的不同阶段对输入或输出进行干预。
中间件的定义方法
# 在users应用中新建一个middleware.py文件
def my_middleware(get_response):
print('init 被调用')
def middleware(request):
print('before request 被调用')
response = get_response(request)
print('after response 被调用')
return response
return middleware
配置
MIDDLEWARE = [
...
'middleware.my_middleware',
]
多个中间件的执行顺序
- 在请求视图被处理前,中间件由上至下依次执行
- 在请求视图被处理后,中间件由下至上依次执行
13. 数据库
ORM
在ORM框架中,它帮我们把类和数据表进行了一个映射,可以让我们通过类和类对象就能操作它所对应的表格中的数据。ORM框架还有一个功能,它可以根据我们设计的类自动帮我们生成数据库中的表格,省去了我们自己建表的过程。
使用django进行数据库开发的步骤如下:
1.配置数据库连接信息
2.在models.py中定义模型类
3.迁移
4.通过类和对象完成数据增删改查操作
配置
在settings.py中保存了数据库的连接配置信息,Django默认初始配置使用sqlite数据库。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
如果要使用 MySQL
- 使用MySQL数据库首先需要安装驱动程序
pip install PyMySQL
- 在Django的工程同名子目录的__init__.py文件中添加如下语句
from pymysql import install_as_MySQLdb
install_as_MySQLdb()
# 作用是让Django的ORM能以mysqldb的方式来调用PyMySQL。
- 修改DATABASES配置信息
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1', # 数据库主机
'PORT': 3306, # 数据库端口
'USER': 'root', # 数据库用户名
'PASSWORD': 'mysql', # 数据库用户密码
'NAME': 'django_demo' # 数据库名字
}
}
- 在MySQL中创建数据库
create database django_demo default charset=utf8;
14. 定义模型类
- 模型类被定义在"应用/models.py"文件中。
- 模型类必须继承自Model类,位于包django.db.models中。
创建应用 booktest 在 models.py 文件中定义模型类。
from django.db import models
#定义图书模型类BookInfo
class BookInfo(models.Model):
btitle = models.CharField(max_length=20, verbose_name='名称')
bpub_date = models.DateField(verbose_name='发布日期')
bread = models.IntegerField(default=0, verbose_name='阅读量')
bcomment = models.IntegerField(default=0, verbose_name='评论量')
is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
class Meta:
db_table = 'tb_books' # 指明数据库表名
verbose_name = '图书' # 在admin站点中显示的名称
verbose_name_plural = verbose_name # 显示的复数名称
def __str__(self):
"""定义每个数据对象的显示信息"""
return self.btitle
#定义英雄模型类HeroInfo
class HeroInfo(models.Model):
GENDER_CHOICES = (
(0, 'male'),
(1, 'female')
)
hname = models.CharField(max_length=20, verbose_name='名称')
hgender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性别')
hcomment = models.CharField(max_length=200, null=True, verbose_name='描述信息')
hbook = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name='图书') # 外键
is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
class Meta:
db_table = 'tb_heros'
verbose_name = '英雄'
verbose_name_plural = verbose_name
def __str__(self):
return self.hname
- 数据库表名
模型类如果未指明表名,Django默认以 小写app应用名_小写模型类名 为数据库表名。
- 主键
django会为表创建自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后django不会再创建自动增长的主键列。
- 属性命名限制
- 不能是python的保留关键字。
- 不允许使用连续的下划线,这是由django的查询方式决定的。
- 定义属性时需要指定字段类型,通过字段类型的参数指定选项,语法如下:
属性=models.字段类型(选项)
- 字段类型
类型 | 说明 |
---|---|
AutoField | 自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性 |
BooleanField | 布尔字段,值为True或False |
NullBooleanField | 支持Null、True、False三种值 |
CharField | 字符串,参数max_length表示最大字符个数 |
TextField | 大文本字段,一般超过4000个字符时使用 |
IntegerField | 整数 |
DecimalField | 十进制浮点数, 参数max_digits表示总位数, 参数decimal_places表示小数位数 |
FloatField | 浮点数 |
DateField | 日期, 参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为False; 参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为False; 参数auto_now_add和auto_now是相互排斥的,组合将会发生错误 |
TimeField | 时间,参数同DateField |
DateTimeField | 日期时间,参数同DateField |
FileField | 上传文件字段 |
ImageField | 继承于FileField,对上传的内容进行校验,确保是有效的图片 |
- 选项
选项 | 说明 |
---|---|
null | 如果为True,表示允许为空,默认值是False |
blank | 如果为True,则该字段允许为空白,默认值是False |
db_column | 字段的名称,如果未指定,则使用属性的名称 |
db_index | 若值为True, 则在表中会为此字段创建索引,默认值是False |
default | 默认 |
primary_key | 若为True,则该字段会成为模型的主键字段,默认值是False,一般作为AutoField的选项使用 |
unique | 如果为True, 这个字段在表中必须有唯一值,默认值是False |
null是数据库范畴的概念,blank是表单验证范畴的
- 外键
在设置外键时,需要通过on_delete选项指明主表删除数据时,对于外键引用表数据如何处理,在django.db.models中包含了可选常量:
- CASCADE 级联,删除主表数据时连同一起删除外键表中数据
- PROTECT 保护,通过抛出ProtectedError异常,来阻止删除主表中被外键应用的数据
- SET_NULL 设置为NULL,仅在该字段null=True允许为null时可用
- SET_DEFAULT 设置为默认值,仅在该字段设置了默认值时可用
- SET() 设置为特定值或者调用特定方法,如
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models
def get_sentinel_user():
return get_user_model().objects.get_or_create(username='deleted')[0]
class MyModel(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET(get_sentinel_user),
)
- DO_NOTHING 不做任何操作,如果数据库前置指明级联性,此选项会抛出IntegrityError异常
15. 迁移
将模型类同步到数据库中。
python manage.py makemigrations
python manage.py migrate
16. 演示工具的使用
shell 工具
python manage.py shell
17. 数据库的操作
(1) 增加
save
>>> hero = HeroInfo(
hname='孙悟空',
hgender=0,
hbook=book
)
>>> hero.save()
create
>>> HeroInfo.objects.create(
hname='沙悟净',
hgender=0,
hbook=book
)
<HeroInfo: 沙悟净>
(2) 查询
基本查询
get 查询单一结果,如果不存在会抛出模型类.DoesNotExist异常。
all 查询多个结果。
count 查询结果数量。
>>> BookInfo.objects.all()
<QuerySet [<BookInfo: 射雕英雄传>, <BookInfo: 天龙八部>, <BookInfo: 笑傲江湖>, <BookInfo: 雪山飞狐>, <BookInfo: 西游记>]>
>>> book = BookInfo.objects.get(btitle='西游记')
>>> book.id
5
>>> BookInfo.objects.get(id=3)
<BookInfo: 笑傲江湖>
>>> BookInfo.objects.get(pk=3)
<BookInfo: 雪山飞狐>
>>> BookInfo.objects.get(id=100)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/delron/.virtualenv/dj/lib/python3.6/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/delron/.virtualenv/dj/lib/python3.6/site-packages/django/db/models/query.py", line 380, in get
self.model._meta.object_name
db.models.DoesNotExist: BookInfo matching query does not exist.
>>> BookInfo.objects.count()
6
过滤查询
实现SQL中的where功能,包括
- filter 过滤出多个结果
- exclude 排除掉符合条件剩下的结果
模型类属性名__条件名 = 值
<<< 相等
BookInfo.objects.filter(id__exact=1)
# 可简写为:
BookInfo.objects.filter(id=1)
<<< 模糊查询
BookInfo.objects.filter(btitle__contains='传')
>BookInfo.objects.filter(btitle__endswith='部')
>以上运算符都区分大小写,在这些运算符前加上i表示不区分大小写,如iexact、icontains、istartswith、iendswith.
<<< 空查询
BookInfo.objects.filter(btitle__isnull=False)
<<< 比较查询
- gt 大于 (greater then)
- gte 大于等于 (greater then equal)
- lt 小于 (less then)
- lte 小于等于 (less then equal)
BookInfo.objects.filter(id__gt=3)
不等于的运算符,使用exclude()过滤器。
BookInfo.objects.exclude(id=3)
<<< 日期查询
year、month、day、week_day、hour、minute、second:对日期时间类型的属性进行运算。
BookInfo.objects.filter(bpub_date__year=1984)
>BookInfo.objects.filter(bpub_date__gt=date(1994, 1, 1))
F 对象(比较两个属性)
django.db.models.F 相对于Field
一般用于查询条件等号后面,代表一个字段
from django.db.models import F
BookInfo.objects.filter(bread__gte=F('bcomment') * 2)
Q 对象(&且|或~非)
django.db.models.Q 相对于Query
一般用于条件的复用
BookInfo.objects.filter(Q(bread__gt=20) | Q(pk__lt=3))
BookInfo.objects.filter(~Q(pk=3))
聚合函数
- 聚合查询
把多条记录转为一个结果,称作聚合
aggregate函数来进行聚合
- 聚合对象
django.db.models.Sum\Max\Min\Avg\
- 返回值
只有一个键值对的字典
键的规则是构造聚合对象的内容__聚合类名的小写
<<< Count
>>> BookInfo.objects.all().aggregate(Count('id'))
{'id__count': 7}
<<< Max
>>> BookInfo.objects.all().aggregate(Max('bread'))
{'bread__max': 58}
<<< Min
>>> BookInfo.objects.all().aggregate(Min('bcomment'))
{'bcomment__min': 0}
<<< Avg
>>> BookInfo.objects.all().aggregate(Avg('bread'))
{'bread__avg': 18.0}
<<< Sum
>>> BookInfo.objects.all().aggregate(Sum('bread'))
{'bread__sum': Decimal('28')}
排序
使用order_by对结果进行排序
BookInfo.objects.all().order_by('bread') # 升序
BookInfo.objects.all().order_by('-bread') # 降序
关联查询
- 通过模型对象查询
- 有一了,通过 模型名称_set.all() 查询多的所有对象
- 有多了,通过 关联属性 查询一的对象
book = BookInfo.objects.get(id=1)
book.heroinfo_set.all()
# HeroInfo.objects.filter(hbook__id=1)
hero =HeroInfo.objects.get(id=1)
hero.hbook
# BookInfo.objects.filter(heroinfo__id=1)
- 通过objects查询
- 先确定要查什么信息,就用什么模型的objects
- 再看查询条件
- 如果当前模型类中有另一个的关联属性,则 关联属性__字段__条件
- 如果当前模型类中没有另一个的关联属性,则 类名__字段__条件
BookInfo.objects.filter(heroinfo__hcomment__contains='八')
HeroInfo.objects.filter(hbook__btitle='天龙八部')
(3) 修改
save
hero = HeroInfo.objects.get(hname='猪八戒')
hero.hname = '猪悟能'
hero.save()
update
HeroInfo.objects.filter(hname='沙悟净').update(hname='沙僧')
(4) 删除
hero = HeroInfo.objects.get(id=13)
hero.delete()
HeroInfo.objects.filter(id=14).delete()
18. 查询集 QuerySet
查询集,也称查询结果集、QuerySet,表示从数据库中获取的对象集合。
当调用如下过滤器方法时,Django会返回查询集(而不是简单的列表):
- all():返回所有数据。
- filter():返回满足条件的数据。
- exclude():返回满足条件之外的数据。
- order_by():对结果进行排序。
对查询集可以再次调用过滤器进行过滤,如
BookInfo.objects.filter(bread__gt=30).order_by('bpub_date')
exists():判断查询集中是否有数据,如果有则返回True,没有则返回False。
两大特性
- 惰性执行
创建查询集不会访问数据库,直到调用数据时,才会访问数据库
# 例如,当执行如下语句时,并未进行数据库查询,只是创建了一个查询集qs
qs = BookInfo.objects.all()
# 继续执行遍历迭代操作后,才真正的进行了数据库的查询
for book in qs:
print(book.btitle)
- 缓存
使用同一个查询集,第一次使用时会发生数据库的查询,然后Django会把结果缓存下来,再次使用这个查询集时会使用缓存的数据,减少了数据库的查询次数。
限制查询集
qs = BookInfo.objects.all()[0:2]
不支持负向索引
19. 管理器 Manager
自定义管理器
- 修改原始查询集,重写all()方法。
a)打开booktest/models.py文件,定义类BookInfoManager
#图书管理器
class BookInfoManager(models.Manager):
def all(self):
#默认查询未删除的图书信息
#调用父类的成员语法为:super().方法名
return super().filter(is_delete=False)
b)在模型类BookInfo中定义管理器
class BookInfo(models.Model):
...
books = BookInfoManager()
c)使用方法
BookInfo.books.all()
- 在管理器类中补充定义新的方法
a)打开booktest/models.py文件,定义方法create。
class BookInfoManager(models.Manager):
#创建模型类,接收参数为属性赋值
def create_book(self, title, pub_date):
#创建模型类对象self.model可以获得模型类
book = self.model()
book.btitle = title
book.bpub_date = pub_date
book.bread=0
book.bcommet=0
book.is_delete = False
# 将数据插入进数据表
book.save()
return book
b)为模型类BookInfo定义管理器books语法如下
class BookInfo(models.Model):
...
books = BookInfoManager()
c)调用语法如下:
book=BookInfo.books.create_book("abc",date(1980,1,1))