ORM框架
- O是object,也就是类或者对象的意思,这里的类就是模型类
- R是relation,也就是关系数据库中数据表的意思
- M是mapping,也就是映射的意思
- 在ORM框架中,它帮我们把模型类和数据表进行了一个映射,可以让我们通过模型类及对象就能操作它所对应的数据表中的数据
- ORM框架它还可以根据我们设计的模型类自动帮我们生成数据库中对应的数据表,省去了我们自己建表的过程
- Django框架中内嵌了ORM框架,所以在使用Django框架时,我们不需要直接面向数据库编程
而是定义模型类,通过模型类及对象完成数据表的增删改查操作
ORM框架作用:
- 帮助Django的开发者以面向对象的思想去操作数据库。
- 并且ORM框架也帮助程序员屏蔽了数据库之间的差异。
1 . 新增
增加数据有两种方法。
1)save
通过创建模型类对象,执行对象的save()方法保存到数据库中。
class TestModel(View):
def get(self, request):
book = BookInfo()
book.btitle = "西游记"
book.bpub_date = "2021-5-20"
book.bread = 20
book.bcomment = 30
# 注意点:使用逻辑删除不要赋值
book.save()
return HttpResponse('test')
2)create
通过模型类.objects.create()保存。
class TestModel(View):
def get(self, request):
BookInfo.objects.create(
btitle = "三国志",
bpub_date = "2021-6-20",
bread = 20,
bcomment = 30)
return HttpResponse('test')
进入create()方法源码可以看出,create方法实际上是对save方法的封装,本质还是要调用save方法
def create(self, **kwargs):
"""
Create a new object with the given kwargs, saving it to the database
and returning the created object.
"""
obj = self.model(**kwargs)
self._for_write = True
obj.save(force_insert=True, using=self.db)
return obj
源码解析:
2. 修改
修改更新有两种方法
1)save
模型对象.save()
class TestModel(View):
def get(self, request):
info = BookInfo.objects.get(id=9)
# 新值覆盖就旧值
info.btitle = '东游记'
# 同步数据
info.save()
return HttpResponse('test')
2)update
使用模型类.objects.filter(‘条件’).update(模型属性=新值),会返回受影响的行数
class TestModel(View):
def get(self, request):
BookInfo.objects.filter(id=9).update(bread=30)
return HttpResponse('test')
注意:新增和修改都用到了save,并不是说save就是新增或者修改,save只是把数据同步到数据库的一个操作
3. 删除
删除有两种方法
1)模型类.objects.filter().delete()
class TestModel(View):
def get(self, request):
BookInfo.objects.filter(id=9).delete()
return HttpResponse('test')
2)模型类对象delete
class TestModel(View):
def get(self, request):
info = BookInfo.objects.get(id=9)
info.delete()
return HttpResponse('test')
以上两种是物理删除,执行完会从数据库中直接删除。工作中基本不会这样直接删除数据,一般会使用逻辑删除
class TestModel(View):
def get(self, request):
info = BookInfo.objects.get(id=8)
info.is_delete = True
info.save()
return HttpResponse('test')
比如我要实现一个获取用户收货地址列表,可以这样写
login_user = request.user
login_user.address.filter(is_delete=False)
4. 查询
4.1 get 查询单一结果,返回的是模型对象,如果不存在会抛出模型类.DoesNotExist异常。所有在使用get方法的时候要捕获异常
class TestQuery(View):
def get(self, request):
info = BookInfo.objects.get(id=1)
print(info.id)
return HttpResponse('test')
结果:
1
4.2 all 查询所有结果。(不加条件)
class TestQuery(View):
def get(self, request):
info = BookInfo.objects.all()
print(info)
return HttpResponse('test')
#查询到的是QuerySet
另外:在模型类中定义的__str__方法,用于返回当前查询对象的信息
def __str__(self):
"""定义每个数据对象的显示信息,就是在输出的时候想看到当前记录的什么信息"""
return self.btitle # 输出该模型数据对象时,只输出书名
4.3 过滤查询实现SQL中的where功能
filter 过滤出多个结果
过滤条件的语法:模型类.objects.filter(属性_条件表达式=值)
1)相等
exact:表示判等。
class TestQuery(View):
def get(self, request):
info = BookInfo.objects.filter(btitle__exact='天龙八部')
print(info)
return HttpResponse('test')
结果
<QuerySet [<BookInfo: 天龙八部>, <BookInfo: 天龙八部>]>
2)模糊查询
contains:是否包含。
startswith、endswith:以指定值开头或结尾。
class TestQuery(View):
def get(self, request):
info = BookInfo.objects.filter(btitle__contains='天')
print(info)
return HttpResponse('test')
结果
<QuerySet [<BookInfo: 天龙八部>, <BookInfo: 天龙八部>]>
就相当于这个: select * from tb_bookinfo where btitle like %like%
3) 空查询
isnull:是否为null。
class TestQuery(View):
def get(self, request):
info = BookInfo.objects.filter(btitle__isnull=False)
print(info)
return HttpResponse('test')
# 查询书名不为空的数据
4) 范围查询
in:是否包含在范围内。
class TestQuery(View):
def get(self, request):
#[1, 3, 5] 这是或者的意思,1或3,或5
info = BookInfo.objects.filter(id__in=[1, 3, 5])
print(info)
return HttpResponse('test')
结果
<QuerySet [<BookInfo: 射雕英雄传>, <BookInfo: 笑傲江湖>, <BookInfo: 射雕英雄传>]>
5)比较查询
- gt 大于 (greater then)
- gte 大于等于 (greater then equal)
- lt 小于 (less then)
- lte 小于等于 (less then equal)
#查询id大于3的
class TestQuery(View):
def get(self, request):
info = BookInfo.objects.filter(id__gt=3)
print(info)
return HttpResponse('test')
# 查询日期大于1990-1-1
class TestQuery(View):
def get(self, request):
info = BookInfo.objects.filter(bpub_date__gt='1990-1-1')
info = BookInfo.objects.filter(bpub_date__gt=date(1990, 1, 1))
info = BookInfo.objects.filter(bpub_date__year=1990)
print(info)
return HttpResponse('test')
不等于的运算符,使用exclude()过滤器。
class TestQuery(View):
# 查询id不等于3的
def get(self, request):
info = BookInfo.objects.exclude(id=3)
print(info)
return HttpResponse('test')
- filter查询满足条件的数据
- exclude查询满足条件以外的数据
5.F对象
之前的查询都是对象的属性与常量值比较,两个属性怎么比较呢?
查询阅读量大于评论量的图书。
class TestQuery(View):
def get(self, request):
info = BookInfo.objects.filter(bread__gt=F('bcomment'))
print(info)
return HttpResponse('test')
可以在F对象上使用算数运算。
BookInfo.objects.filter(bread__gt=F('bcomment') * 2)
6.Q对象
实现逻辑或(or),逻辑非(not),逻辑与(and)的查询
逻辑与(and)
Q对象可以使用&、|连接,&表示逻辑与,|表示逻辑或。
class TestQuery(View):
def get(self, request):
#查询阅读量大于20,并且编号小于3的图书。
info = BookInfo.objects.filter(bread__gt=20,id__lt=4)
print(info)
return HttpResponse('test')
逻辑或(or),需要使用Q()对象结合|运算符
class TestQuery(View):
def get(self, request):
#查询阅读量大于20,或者编号小于3的图书。
info = BookInfo.objects.filter(Q(bread__gt=20) | Q(id__lt=4))
print(info)
return HttpResponse('test')
Q对象前可以使用~操作符,表示非not。
例:查询编号不等于3的图书。
BookInfo.objects.filter(~Q(pk=3))
7.聚合函数
使用aggregate()过滤器调用聚合函数。聚合函数包括:Avg 平均,Count 数量,Max 最大,Min 最小,
from django.db.models import Sum
BookInfo.objects.aggregate(Sum('bread'))
注意aggregate的返回值是一个字典类型,格式如下:
{'属性名__聚合类小写':值}
如:{'bread__sum':3}
8.排序
使用order_by对结果进行排序
BookInfo.objects.all().order_by('bread') # 升序
BookInfo.objects.all().order_by('-bread') # 降序
9 关联查询
由一到多的访问语法:在这里插入代码片
一对应的模型类对象.多对应的模型类名小写_set
例:
b = BookInfo.objects.get(id=1)
b.heroinfo_set.all()
b.heroinfo_set.filter()
由多到一的访问语法:
多对应的模型类对象.关联类属性_id (外键)
例:
h = HeroInfo.objects.get(id=1)
h.hbook_id
查询集QuerySet
1. 概念
Django的ORM中存在查询集的概念。
查询集,也称查询结果集、QuerySet,表示从数据库中获取的对象集合。
当调用如下过滤器方法时,Django会返回查询集(而不是简单的列表):
- all():返回所有数据。
- filter():返回满足条件的数据。
- exclude():返回满足条件之外的数据。
- order_by():对结果进行排序。
对查询集可以再次调用过滤器进行过滤,如
BookInfo.objects.filter(bread__gt=30).order_by('bpub_date')
从SQL的角度讲,查询集与select语句等价,过滤器像where、limit、order by子句。
判断某一个查询集中是否有数据:
- exists():判断查询集中是否有数据,如果有则返回True,没有则返回False。
2. 两大特性
1)惰性执行
创建查询集不会访问数据库,直到调用数据时,才会访问数据库,调用数据的情况包括迭代、序列化、与if合用
例如,当执行如下语句时,并未进行数据库查询,只是创建了一个查询集qs
(如果服务器数据上百万,频繁操作数据库会对数据库产生很大的压力)
qs = BookInfo.objects.all()
继续执行遍历迭代操作后,才真正的进行了数据库的查询
for book in qs:
print(book.btitle)
2)缓存
使用同一个查询集,第一次使用时会发生数据库的查询,然后Django会把结果缓存下来,再次使用这个查询集时会使用缓存的数据,减少了数据库的查询次数。