9、Django_ORM_数据的创建以及增删改查

一、查询集QuerySet

  • 什么是查询集?
    查询集:从数据库查询得到的模型对象集合QuerySet,是一个列表
  • 什么是过滤器?
    过滤器:基于查询集得到的结果上进一步进行条件筛选过滤结果

二、过滤器

返回list/多个结果的过滤器
  • values = model名称.objects.all():返回所有数据;返回查询集QuerySet对象。因为是列表,所以其结果可以使用values[索引].字段名获取数据。注意不支持负索引
  • model名称.objects.retrieve():获取数据表中的所有记录,也就是返回查询集QuerySet对象
  • model名称.objects.filter():返回满足条件的数据
  • model名称.objects.exclude():返回满足条件之外的数据
  • model名称.objects.order_by():返回排序后的结果
返回一个对象的过滤器
  • model名称.objects.get():返回一个model类,而不是str
    1.如果查询不到对应的结果, 则会抛出模型类.DoesNotExist异常
    2.如果返回多条结果,则会抛出模型类.MultipleObjectsReturned异常
  • model名称.objects.count():返回满足查询结果的总条数
  • model名称.objects.aggregate():返回集合
  • model名称.objects.exists():判断返回的查询集中是否有数据,没有则False,有则True
    PS.
    1.过滤器往往会和查询条件结合使用进行查询
    2.一般情况用 model名称.objects,但也会指定对象,比如说polls.address.
查询集的特点
  • 非立刻执行
    1.创建查询集时,并不会访问数据库。而是直到模板中调用到数据时,才会进行数据库的访问。
  • 缓存
    1.查询集的结果会被保存下来,再次查询相同的数据时,会使用之前保存下来的结果数据
    2.每个查询集都会有一个缓存空间来保存查询结果数据
    3.切片和索引操作没有缓存可用,每次都会实际去执行sql语句
查询集索引

当查询集返回的是列表时,就可以使用下标的方式来获取我们想要的内容。

def AddressAPI(request):
    # 获取第2、3、4项
    address_values = AddressInfo.objects.all()[1:3]
    # 构造上下文
    context = {F'AddressInfo:{address_values}'}
    return render(request, 'address.html', context)

三、查询集的查询条件

  • 查询语句:模型属性/表字段__条件运算符=值
    1.查询语句由三部分组成:模型属性/表字段+两个下划线__+条件运算符,所以在定义属性模型/表字段时,不能定义包括多个下划线的名字
    2.想要实现SQL中的where功能,可以使用过滤器filter()exclude()get()
  • 条件运算符
    1.exact:判断相等
address = AddressInfo.objects.filter(id__exact = 1)  # 查询id为1的地址

2.contains:判断包含

address = AddressInfo.objects.filter(name__contains = '广')  # 查询地址名称有广的地址

3.startswith/endswith:以什么开头/结尾
4.isnull:是否为null

address = AddressInfo.objects.filter(pid__isnull = true)  # 查询pid为null的地址

5.in:是否包含在范围内

address = AddressInfo.address.filter(id__in = [1,3])  # 查询id为1或3的地址

6.gt、gte、lt、lte:大于、大于等于、小于、小
7.exclude:条件以外的数据

address = AddressInfo.objects.filter(id__exclude = 1)   # 查询id不为1的地址

8.year、month、day、week_day、hour、minute、second:对日期时间类型的属性进行查询

books = BookInfo.objects.filter(pub_time__year = 2000)  # 查询2000年发表的书籍

9.datetime.date

from datetime import date
books = BookInfo.objects.filter(pub_time__gt = date(2000,1,1))  # 查询2000年1月1号以后发布的书籍

10.多条件查询:或(使用|隔开查询条件)

BookInfo.objects.filter(id__gt = 1 | pub_time__year = 2000)  # 查询id大于1或发布年份是2000年的数据

11.多条件查询:与(使用,隔开查询条件)

BookInfo.objects.filter(id__gt = 1 , pub_time__year = 2000)  # 查询id大于1,并且发布年份是2000年的数据

12.链式查询:多个filter()进行查询(其它过滤器也可以这样)

BookInfo.objects.filter(id__gt = 1).filter(pub_time__year = 2000) # 在查询id大于1的结果集上,再查询发布年份是2000年的数据

13.获取查询集的第一个元素以及最后一个元素:first()last()

BookInfo.objects.filter(id__gt = 1).first()
BookInfo.objects.filter(id__gt = 1).last()

14.排序order_by('字段/-字段')

BookInfo.objects.filter(id__gt = 1).order_by('name') # 结果按照name排序,ascall码从小到大
BookInfo.objects.filter(id__gt = 1).order_by('-name') # 结果按照name排序,ascall码从大到小
BookInfo.objects.filter(id__gt = 1).order_by('id', 'name') # 结果先按照id排序,如果相同,则按照name排序

PS.
1.exact、contains、startswith、endswith这几个运算符都区分大小写,如需不区分大小写,只需要在前面加上i即可:iexact、icontains、istartswitch、iendswith

四、F对象和Q对象

  • F对象用于两个属性进行比较,并且支持运算
    1.语法:
from django.db.models import F
F("属性名/表字段")

2.例子
2.1.查询评论量大于阅读量的书籍

books = BookInfo.objects.filter(commentcount__gt = F('readcount'))

2.2.查询评论量大于阅读量2倍的书籍

books = BookInfo.objects.filter(commentcount__gt = F('readcount' * 2))
  • Q对象类似sql语句的where中的andor
    1.语法
from django.db.models import Q
# |:或
Q(属性名/表字段1__条件运算符=值) |  Q(属性名/表字段2__条件运算符=值)   # 查询满足第一个条件或第二个条件的数据
# ,:且
Q(属性名/表字段1__条件运算符=值) ,  Q(属性名/表字段2__条件运算符=值)  # 查询满足第一个条件和第二个条件的数据
# 组合
Q(属性名/表字段1__条件运算符=值) ,  Q(属性名/表字段2__条件运算符=值)  |  Q(属性名/表字段3__条件运算符=值)  # 查询满足条件1且(条件2或条件3)的数据

2.1.或:|

books = BookInfo.objects.filter(Q(readcount__gt = 10) | Q(id__lt) = 5)  # 查询阅读量大于10或id小于5的书籍

2.2.且:,

books = BookInfo.objects.filter(Q(readcount__gt = 10) , Q(id__lt) = 5)  # 查询阅读量大于10且id小于5的书籍

2.3.不等于/取反:~

books = BookInfo.objects.filter(~Q(readcount__gt = 10) , Q(id__lt) = 5)  # 查询阅读量小于等于10且id小于5的书籍

2.4.组合

PS.如果有其它关键字条件,Q对象需要在关键字条件后面

books = BookInfo.objects.filter(pub_time = 2000 , Q(id__lt) = 5)  # pub_time是关键字

关于Q对象更详细看文章:https://www.cnblogs.com/huchong/p/8027962.html

五、聚合函数

  • aggregate()过滤器调用聚合函数,然后返回单个对象
  • 聚合函数:Avg('属性名/表字段')Max('属性名/表字段')Min('属性名/表字段')Sum('属性名/表字段')Count('属性名/表字段')。使用Count('属性名/表字段')时,一般情况下是直接调用,不需要使用aggregate()函数
  • 聚合函数在django.db.models导入
  • 例子(注意上下文字典中,总阅读量的key的书写规则)
from django.db.models import Sum

def books(request):
    # 统计所有书籍的总阅读量
    readcount = BookInfo.objects.aggregate(Sum('readcount'))
    # 构造上下文
    context = {'readcount': readcount}
    return  render(request, 'Book/book.html', context)

六、关联查询(objects前面用的是哪个class,返回的就是哪个class对象)

一对多、多对多关联查询(基础关联)
  • 查询方老师所教的所有课程
 # 先查询方老师
teacher = Teacher.objects.get(nickname = '方老师')
# 再通过方老师查询所有相关的任务信息
classInfo = teacher.classinfo_set.all()
  • 查询python课程的老师
# 先查询课程
class = ClassInfo.object.get(title = 'python课程')
# 再通过关联查询对应的老师
teacher = class.teacher
内连接查询
  • 语法:外键字段名__从表字段名__条件关联模型类名小写__属性名__运算符=值,结果和sql中的inner join相同(内连接)
  • 查询书名为"红楼梦"的所有人物信息(peopleInfo)
    通过书找关联的人
# 原始内连接sql语句:
select p.name, b.name from peopleinfo as p inner join bookinfo as b on p.book_id = b.id where b.name = "红楼梦";

对应语句:

peopleInfos = PeopleInfo.objects.filter(book__name='红楼梦')
  • 查询书籍中人物的描述包含"红"的书籍
    通过人找关联的书
bookInfos = BookInfo.books.filter(peopleinfo__description__contains='红')
自关联查询

自关联的表结构:对于地区信息、分类信息等数据,表结构非常类似,每个表的数据量十分有限,为了充分利用数据表的大量数据存储功能,可以设计成一张表,内部的关系字段指向本表的主键
说明:关系属性使用self指向本类,要求null和blank允许为空,因为一级数据是没有父级的
更多看之前的文章:https://www.jianshu.com/p/08c1be3dc9b2

七、LIKE语句中转义百分符号和下划线

在sql语句中,%有特殊的作用,Django可以转义%_,这样就可以和普通字符一样使用

xxx.objects.filter(headline__contains='%')
# 相当于sql:
SELECT ... WHERE headline LIKE '%\%%';

八、创建数据/生成数据表中的数据

  • 创建和保存对象
#### 方法1
# 1.创建模型类对象,此时sql还未执行
one_value = Userinfo(username='hello', password='hi')
# 2.调用save方法,执行sql语句,生成数据
one_value.save()

#### 方法2
# 执行sql语句,生成数据,返回的是模型类对象
Userinfo.objects.create(username='hi', password='hello')
  • 保存外键字段
    保存外键字段和保存普通字段一样,只不过给外键字段赋值的时候迅速要注意类型要正确
  • 保存多对多字段
    需要调用add()方法,而不是直接给属性赋值,不过不需要调用save()方法
from .model.animal import Animal
from .model.cat import Cat

animal = Animal.objects.get(pk = 1)
cat1 = Cat.objects.create(named='xiaomi')  
cat2 = Cat.objects.create(named='xiaohei')

animal.cats.add(cat1, cat2)    # 保存多对多字段

八、修改数据和更新数据

  • 修改数据:先获取数据,然后修改数据,再保存数据(一般用于外键/ForeignKey的修改)
value = Animal.objects.get(id=1)
value.namede = 'haha'
value.save()
  • 更新数据:update()
    1.可以批量为QuerySet中所有的对象进行更新操作
    2.只能对普通字段和ForeignKey字段使用
    3.对ForeignKey字段使用时,需要设置新值为想要指向的新模型实例
# 普通字段
Animal.objects.filter(id=1).update(named = 'hahaha')
# ForeignKey字段
c = Cat.objects.get(id=2)  # 想要指向的新模型实例
Animal.objects.all().update(cat=c)
  • update()方法会直接转换成一个sql语句,并立刻批量执行,并且不会运行模型的save()方法。如果想要保存QuerySet中的每个条目并确保每个实例的save()方法都被调用,你不需要使用任何特殊的函数来处理。只需要迭代它们并调用save()方法:
for item in my_queryset:
    item.save()
  • update方法可以配合F表达式。这对于批量更新同一模型中某个字段特别有用。例如增加Blog中每个Entry的pingback个数:
    Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)。然而,与filterexclude子句中的F()对象不同,在update中不可以使用F()对象进行跨表操作,只可以引用正在更新的模型的字段。如果尝试使用F()对象引入另外一张表的字段,将抛出FieldError异常:
# THIS WILL RAISE A FieldError
>>> Entry.objects.update(headline=F('blog__name'))

九、删除数据

先获取数据,再删除数据

value = Animal.objects.get(id=1)
value.delete() # 该方法将返回被删除对象的总数量和一个字典,字典包含了每种被删除对象的类型和该类型的数量
# 支持批量删除
Animal.objects.filter(named='haha').delete()
  • 注意
    delete()是唯一没有在管理器上暴露出来的方法。这是刻意设计的一个安全机制,用来防止意外地请求类似Animal.objects.delete()的动作,导致不慎删除了所有的对象数据。如果你确实想删除所有的对象,你必须明确地请求一个完全的查询集,如:
Animal.objecets.all().delete()

PS.本文参考:
https://blog.csdn.net/kan2016/article/details/82868636/https://www.cnblogs.com/huchong/p/8027962.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容