58.2-Django模型之查询集切片过滤器
总结:
- 查询管理器一般至少定义一个 才可以查询;
- 浏览器端发来的数据都不可信;
- 结果集本身就是一个 缓存 ;
- _str_ 是给用户看的,_repr_则是给开发者看的;例如:
str(dog) 'i am kitty'
repr(dog) 'Animal:name is kitty'- 字段命名 禁止使用__;
模型操作
管理器对象
Django会为模型类提供一个objects对象,它是django.db.models.manager.Manager类型,用于与数据库交互(对数据库进行 增删改查)。
Django 的一个强大的功能是它的对象关系映射Object-Relational Mapper(ORM),它允许你就像使用 SQL 一样去和你的数据库交互。事实上,Django 的 ORM 就是创建 SQL 去查询和操作数据库的一个 Python 式方式,并且获得 Python 风格的结果。 我说的是一种方式,但实际上,它是一种非常聪明的工程方法,它利用了 Python 中一些很复杂的部分,而使得开发者更加轻松。
当定义模型类的时候没有指定管理器,则Django会为模型类提供一个objects的管理器。
如果在模型类中手动指定管理器后,Django不再提供默认的objects的管理器了。
管理器是Django的模型进行数据库查询操作的接口,Django应用的每个模型都至少拥有一个管理器。
Django ORM
数据的校验validation是在对象的Save、update方法上
1. 查询
1.1 查询集
查询会返回结果的集, 它是django.db.models.query.Query Set类型。
它是惰性求值, 和sql alchemy一样。结果就是查询的集。
它是可迭代对象。
# blog/user/urls # 设置访问路劲;
from django.conf.urls import url
from .views import reg,show
urlpatterns = [
url(r'^reg$',reg),
url(r'^show$',show)
]
# blog/user/show 中增加
def show(request): # 方法的使用方式各不相同;
query = User.objects.all() # objects
return JsonResponse({})
#-------------------------------------------------------
{}
1、惰性求值:
创建查询集不会带来任何数据库的访问,直到调用方法使用数据时,才会访问数据库。在迭代、序列化、if语句中都会立即求值。2、缓存:
每一个查询集都包含一个缓存,来最小化对数据库的访问。
新建查询集,缓存为空。首次对查询集求值时,会发生数据库查询,Django会把查询的结果存在这个缓存中,并返回请求的结果,接下来对查询集求值将使用缓存的结果。
观察下面的2个例子是要看真正生成的语句了
- 没有使用缓存,每次都要去查库,查了2次库
[user.name for user in User.objects.all()]
[user.name for user in User.objects.all()]
[u for u in User.objects.all()]
[u for u in User.objects.all()]
- 下面的语句使用缓存,因为使用同一个结果集,查一遍;
qs = User.objects.all()
[user.name for user in qs]
[user.name for user in qs]
[u for u in users] # 查一遍
[u for u in users]
1.2 限制查询集(切片)
为了不对数据库多次查询,
在 http://127.0.0.1:8000/admin/user/user/ 增加2个用户
查询集对象可以直接使用索引下标的方式(不支持负索引),相当于SQL语句中的limit和offset子句。
注意使用索引返回的新的结果集,依然是惰性求值,不会立即查询。
qs = User.objects.all()[20:40]
# LIMIT 20 OFFSET 20
users = User.objects.all()[1:]
print(users)# objects
#---------------------------------------
<QuerySet [<User 6 jerry>, <User 7 ben>]>
1.3 过滤器
返回查询集的方法,称为过滤器,如下:
User.objects.-------
名称 | 说明 |
---|---|
all() | |
filter() | 过滤,返回满足条件的数据 |
exclude() | 排除,排除满足条件的数据 |
order_by() | |
values() | 返回一个对象字典的列表,列表的元素是字典,字典内是字段和值的键值对 |
filter(k1=v1).filter(k2=v2) 等价于 filter(k1=v1, k2=v2)
filter(pk=10) 这里pk指的就是主键, 不用关心主键字段名,当然也可以使用使用主键名filter(emp_no=10) 返回单个值的方法
//
users = User.objects.all()
print(users.values())# objects
# ------------------------------------------------------------------
<QuerySet [{'id': 1, 'name': 'tom', 'email': 'tom@magedu.com', 'password': 'tom'}, {'id': 6, 'name': 'jerry', 'email': 'jerry@magedu.com', 'password': 'jerry'}, {'id': 7, 'name':
'ben', 'email': 'ben@a.com', 'password': 'ben'}]>
名称 | 说明 |
---|---|
get() | 仅返回单个满足条件的对象 如果未能返回对象则抛出DoesNotExist异常;如果能返回多条,抛出MultipleObjectsReturned异常 |
count() | 返回当前查询的总条数 |
first() | 返回第一个对象 |
last() | 返回最后一个对象 |
exist() | 判断查询集中是否有数据,如果有则返回True |
user = User.objects.filter(email=email).get() # 期待查询集只有一行,否则抛出异常
user = User.objects.get(pk=2) # 返回不是查询集,而是一个User实例,否则抛出异常
user = User.objects.get(id=1) # 更多的查询使用主键,也可以使用pk=1
user = User.objects.first() # 使用limit 1查询,查到返回一个实例,查不到返回None
user = User.objects.filter(pk=3, email=email).first() # and条件
1.4 字段查询(Field Lookup)表达式
字段查询表达式可以作为filter()、exclude()、get()的参数,实现where子句。
语法: 属性(字段)名称__比较运算符=值
注意:属性名和运算符之间使用双下划线
比较运算符如下
名称 | 举例 | 说明 |
---|---|---|
exact | filter(is deleted=False) filter(is deleted_ _exact=False) |
严格等于,可省略不写 |
contains | exclude(title__contains='天') | 是否包含,大小写敏感,等价于like'%天%' |
statswith endswith |
filter(title__starts with='天' | 以什么开头或结尾,大小写敏感 |
isnull isnotnull |
filter(title__is null=False) | 是否为null |
iexact icontains istartswith i ends with |
i的意思是忽略大小写 | |
in | filter(pk_in=[1, 2, 3, 100] ) | 是否在指定范围数据中 |
gt、gte 大 It、Ite 小 |
filter(id__gt=3) filter(pk__lte=6) filter(pub_date__gt=date(2000, 1, 1) ) |
大于、小于等 |
year、month、day week_day hour、minute、second |
filter(pub_date__year=2000) | 对日期类型属性处理 |
1.5 Q对象
虽然Django提供传入条件的方式,但是不方便,它还提供了Q对象来解决。
Q对象是django.db.models.Q,可以使用&(and)、|(or)操作符来组成逻辑表达式。 ~ 表示not。
from django.db.models import Q
User.objects.filter(Q(pk__lt=6)) # 不如直接写User.objects.filter(pk<6)
User.objects.filter(pk__gt=6).filter(pk_lt=10) # 与
User.objects.filter(Q(pk_gt=6) & Q(pk_lt=10)) # 与
User.objects.filter(Q(pk=6) | Q(pk=10)) # 或
User.objects.filter(~Q(pk__lt=6)) # 非
可使用&|和Q对象来构造复杂的逻辑表达式
过滤器函数可以使用一个或多个Q对象
如果混用关键字参数和Q对象,那么Q对象必须位于关键字参数的前面。所有参数都将and在一起