浅谈Django QuerySet对象(模型.objects)的常用方法


Posted in Python onMarch 28, 2020

准备工作:

新建一个项目,在项目中新家一个app,名字自取。将app添加值settings.py中,然后配置settings连接数据库。

在app中的models中新建模型:

from django.db import models

# Create your models here.
class Author(models.Model):
  """作者模型"""
  name = models.CharField(max_length=100)
  age = models.IntegerField()
  email = models.EmailField()

  class Meta:
    db_table = 'author'


class Publisher(models.Model):
  """出版社模型"""
  name = models.CharField(max_length=300)

  class Meta:
    db_table = 'publisher'


class Book(models.Model):
  """图书模型"""
  name = models.CharField(max_length=300)
  pages = models.IntegerField()
  price = models.FloatField()  #书的定价
  rating = models.FloatField()
  author = models.ForeignKey(Author, on_delete=models.CASCADE)
  publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)

  class Meta:
    db_table = 'book'


class BookOrder(models.Model):
  """图书订单模型"""
  book = models.ForeignKey("Book", on_delete=models.CASCADE)
  price = models.FloatField()   #书卖出去的真正价格

  class Meta:
    db_table = 'book_order'

执行makemigrations后在migrate。

然后手动向表中添加数据,例如我添加的信息:

浅谈Django QuerySet对象(模型.objects)的常用方法

浅谈Django QuerySet对象(模型.objects)的常用方法

浅谈Django QuerySet对象(模型.objects)的常用方法

浅谈Django QuerySet对象(模型.objects)的常用方法

然后配置urls,直至项目运行成功。

1.filter:

过滤,将满足条件的数据提取出来,返回一个新的QuerySet。

2. exclude:

排除,排除满足条件的数据,返回一个新的QuerySet。

例如,取出book中id大于等于2的图书,并且id不能等于3的图书。示例代码:

books = models.Book.objects.filter(id__gt=1).exclude(id=3)

我们也可以使用Q表达式来实现,

from django.db.models import Q
books = models.Book.objects.filter(id__gt=1).filter(~Q(id=3))

3. annotate:

给QuerySet中的每个对象都添加一个使用查询表达式(聚合函数、F表达式、Q表达式、Func表达式等)的新字段。

例如 给每本图书都添加一个字段叫author_name

from django.db.models import F
books = models.Book.objects.annotate(author_name = F('author__name'))

注意:

Book模型下面最开始是没有author_name这个属性的。只有一个author属性连接的一个外键.

author__name是book下的author属性下的name,即book这个表通过外键访问到author这个表中的name值。

执行完上述代码之后就在book中创建了一个新的属性author_name,但是只在内存中,不会映射到数据库中去。

4.order_by:

指定将查询的结果根据某个字段进行排序。如果要倒叙排序,那么可以在这个字段的前面加一个负号。

示例

def index2(request):
  # 1. 将book中的price属性按照从小到大进行排序
  # books = models.Book.objects.order_by('price')
  # for book in books:
  #   print("%s-%s"%(book.name,book.price))

  # 2. 将book中的price属性按照从大到小进行排序
  books = models.Book.objects.order_by('-price')
  for book in books:
    print("%s-%s"%(book.name,book.price))
  return HttpResponse('success')

修改对应注释代码哪呢个查看到效果。

需求:对价格进行排序,价格一样的就按照页数来进行排序,价格从小到大,页数从大到小。为了方便查看效果,可以先去数据库中修改数据。

def index2(request):
  # 1. 将book中的price属性按照从小到大进行排序
  # books = models.Book.objects.order_by('price')
  # for book in books:
  #   print("%s-%s"%(book.name,book.price))

  # 2. 将book中的price属性按照从大到小进行排序
  # books = models.Book.objects.order_by('-price')
  # for book in books:
  #   print("%s-%s"%(book.name,book.price))

  # 3. 对价格进行排序,价格一样的就按照页数来进行排序,价格从小到大,页数从大到小。
  books = models.Book.objects.order_by('price','-pages')
  for book in books:
    print("%s-%s-%s"%(book.name,book.price,book.pages))
  return HttpResponse('success')

注意:

books = models.Book.objects.order_by('price','-pages')不等于books = models.Book.objects.order_by('price').order_by('-pages')

如果使用多个order_by,会把前面排序的规则给打乱,只会使用最后面的一个排序方式。

order_by方法并没有改变数据库中的信息位置,只是我们将数据取出来进行了排序。

那么如果我们对数据库中的信息进行了排序,这样我们就不用每次取数据都需要进行一次排序了。应该怎样做呢?

我们只需要在模型中添加点代码就可以了。

例如:我们在Book者恶搞模型中对价格进行排序,价格一样的就按照页数来进行排序,价格从小到大,页数从大到小。

修改Book中的class Meta中的代码:

class Meta:
    db_table = 'book_order'
    ordering = ['price','-pages']

这样就对数据库中的信息进行了排序,我们在去数据 的时候也不用使用order_by来进行排序了。但是这样需要重新makegrations和migrate一下,这里就不做演示了。

需求:根据每本图书的销量来进行排序

from django.db.models import Q,F,Count

def index2(request):

# 1. 将book中的price属性按照从小到大进行排序
  # books = models.Book.objects.order_by('price')
  # for book in books:
  #   print("%s-%s"%(book.name,book.price))

  # 2. 将book中的price属性按照从大到小进行排序
  # books = models.Book.objects.order_by('-price')
  # for book in books:
  #   print("%s-%s"%(book.name,book.price))

  # 3. 对价格进行排序,价格一样的就按照页数来进行排序,价格从小到大,页数从大到小。
  # books = models.Book.objects.order_by('price','-pages')
  # for book in books:
  #   print("%s-%s-%s"%(book.name,book.price,book.pages))

  # 4. 根据每本图书的销量来进行排序
  results = models.Book.objects.annotate(sale_num=Count('bookorder__id')).order_by('sale_num')
  for result in results:
    print("%s-%s"%(result.name,result.sale_num))
  return HttpResponse('success')

因为Book这个模型中没有sale_num这个属性,所以我们需要使用annotate这个方法来创建一个sale_num属性,然后使用Count方法进行赋值,然后使用order_by 进行排序。就实现了这个需求。

5. values:

用来指定在提取数据出来,需要提取哪些字段。默认情况下会把表中所有的字段全部都提取出来,可以使用values来进行指定,并且使用了values方法后,提取出的QuerySet中的数据类型不是模型,而是在values方法中指定的字段和值形成的字典。

需求: 只需要提取Book中的id 和 name

示例:

def index3(request):

# 1. 只需要提取Book中的id 和 name
  books = models.Book.objects.values('id','name')
  for book in books:
    print(book)
  return HttpResponse('success')

注意: 返回的是一个字典类型。字典的key就是属性名,value是属性值。

需求:提取Book中的name和author__name,并且字典中的key自己指定,不使用默认的。字典的key分别为bookName和authorNmae

def index3(request):

# 1. 只需要提取Book中的id 和 name
  # books = models.Book.objects.values('id','name')
  # for book in books:
  #   print(book)

  # 需求:提取Book中的name和author__name,并且字典中的key自己指定,不使用默认的。
  # 字典的key分别为`bookName`和`authorNmae`
  books = models.Book.objects.values(bookName=F('name'),authorName=F('author__name'))
  for book in books:
    print(book)
  return HttpResponse('success')

注意:

自己取名字不能取该模型的属性名,否则会报错。

如果在value中不传递任何参数,那么会获取这个模型所有的值。返回的还是一个字典。

6:values_list:

类似于values。只不过返回的QuerySet中,存储的不是字典,而是元组。操作和values是一样的,只是返回类型不一样。

注意: 当我们使用此方法只返回一个值的时候,那么这个元祖中只有一个值,我们可以添加一个参数flat=True,将元祖去掉,从而得到一个字符窜。只有当values_list中只有一个值的时候才能使用这个方法:

示例:

books = models.Book.objects.values_list('name',flat=True)

7. all:

获取这个ORM模型的QuerySet对象。即获取所有的数据。

获取Book中所有数据

示例:

books = models.Book.objects.all()

8.select_related:

在提取某个模型的数据的同时,也提前将相关联的数据提取出来。比如提取文章数据,可以使用select_related将author信息提取出来,以后再次使用article.author的时候就不需要再次去访问数据库了。可以减少数据库查询的次数。

def index4(request):
  books = models.Book.objects.select_related('author')
  for book in books:
    print(book.author.name)
  return HttpResponse('succrss')

注意: select_related只能使用在设置了外键的模型中(即只能在一对多模型上,不能多对一,多对多等),比如我们只在Book设置了author外键和publisher外键。那么select_related里面只能传如这两个参数,而不能传入别的参数,如BookOrder,因为我们是在BookOrder中设置的外键连接到Book,并没有在Book中设置外键连接到BookOrder这个模型。

9. prefetch_related:

这个方法和select_related非常的类似,就是在访问多个表中的数据的时候,减少查询的次数。这个方法是为了解决多对一和多对多的关系的查询问题。

需求:从book中通过prefetch_related查询BookOrder中的信息。

示例代码

def index5(request):
  books = models.Book.objects.prefetch_related("bookorder_set")
  for book in books:
    print('*'*30)
    print(book.name)
    orders = book.bookorder_set.all()
    for order in orders:
      print(order.id)
  return HttpResponse('success')

prefetch_related方法也能办到select_related方法能办到的事情,只是select_related方法效率比prefetch_related方法效率高一点。所以能使用select_related方法的话就是用这个方法。但是这两种方法的执行效率都比传统的方法执行效率高。传统的方法就是先返回book对象,再通过book去查询对应的外键的相关信息。

10. defer:

在一些表中,可能存在很多的字段,但是一些字段的数据量可能是比较庞大的,而此时你又不需要,比如我们在获取文章列表的时候,文章的内容我们是不需要的,因此这时候我们就可以使用defer来过滤掉一些字段。这个字段跟values有点类似,只不过defer返回的不是字典,而是模型。

需求:过滤掉book 的name字段

def index6(request):
  # 过滤掉book的name字段
  books = models.Book.objects.defer('name')
  for book in books:
    print(book.id)

  return HttpResponse('sucdess')

注意: 我们在使用defer过滤掉name字段之后,我们还是可以访问到name属性,是因为当我们访问name属性的时候,Django又去执行了一遍sql语句查询的代码。所以在我们开发的过程中,除非我们确定不会使用到此属性,否则不要去过滤它。

defer虽然能过滤字段,但是有些字段是不能过滤的,比如id,即使你过滤了,也会提取出来。

11. only:

跟defer类似,只不过defer是过滤掉指定的字段,而only是只提取指定的字段。

需求:只提取name属性

# 只提取name属性
  books = models.Book.objects.only('name')
  for book in books:
    print(book.id,book.name)

注意: id这个字段我们是不能操作的,像上面一样,我们没有提取id属性,但是还是给我们提取出来了。所以id属性是一定会被提取出来的。

和defer一样,就算我们没有提取某个属性出来,我们还是可以访问到的,只是会重新执行一遍sql代码而已。

12. get:

获取满足条件的数据。这个函数只能返回一条数据,并且如果给的条件有多条数据,那么这个方法会抛出MultipleObjectsReturned错误,如果给的条件没有任何数据,那么就会抛出DoesNotExit错误。所以这个方法在获取数据的只能,只能有且只有一条。

# 获取id为1的数据
book = models.Book.objects.get(id=1)

13. create:

创建一条数据,并且保存到数据库中。这个方法相当于先用指定的模型创建一个对象,然后再调用这个对象的save方法。

publusher = models.Publisher.objects.create(name='知了出版社')

14. get_or_create:

根据某个条件进行查找,如果找到了那么就返回这条数据,如果没有查找到,那么就创建一个。

result = models.Publisher.objects.get_or_create(name='知了出版社')
print(result)

会返回一个元祖

查找的对象以及是否创建了这条数据。False就是没有创建这条数据。

15. bulk_create:

和create方法类似,只是这个方法可以一次性创建多个数据。

publusher = models.Publisher.objects.bulk_create([models.Publisher(name='123出版社'),
models.Publisher(name='abc出版社'),])

16. count:

获取提取的数据的个数。如果想要知道总共有多少条数据,那么建议使用count,而不是使用len(articles)这种。因为count在底层是使用select count(*)来实现的,这种方式比使用len函数更加的高效。

count = models.Book.objects.filter(name='xxx').count()

17. first和last:

返回QuerySet中的第一条和最后一条数据。如果为空则返回none。

18. aggregate:

使用聚合函数。

19. exists:

判断某个条件的数据是否存在。如果要判断某个条件的元素是否存在,那么建议使用exists,这比使用count或者直接判断QuerySet更有效得多。

示例代码如下:

# 最高效的判断值是否存在的方法
if Article.objects.filter(name='三国演义').exists():
  print(True)
# 比上面的方法效率低一点
if Article.objects.filter(name='三国演义').count() > 0:
  print(True)
# 还要比上面的效率低
if Article.objects.filter(name='三国演义'):
  print(True)

20. distinct:

去除掉那些重复的数据。这个方法如果底层数据库用的是MySQL,那么不能传递任何的参数。

需求:提取所有销售的价格超过80元的图书,并且删掉那些重复的,那么可以使用distinct来帮我们实现,示例代码如下:

books = models.Book.objects.filter(bookorder__price__gte=80).distinct()
  for book in books:
    print(book.name)

并且distinct只会剔除那些完全相同的数据,如果有一个字段不相同,都不会剔除的。

如果在distinct之前使用了order_by,那么因为order_by会提取order_by中指定的字段,因此再使用distinct就会根据多个字段来进行唯一化,所以就不会把那些重复的数据删掉。

示例:

orders = models.BookOrder.objects.order_by("pages").values("book_id").distinct()

21. update:

执行更新操作,在SQL底层走的也是update命令。比如要将所有图书的价格都提高10元。

book = models.Book.objects.update(price=F('price')+5)

22. delete:

删除所有满足条件的数据。删除数据的时候,要注意on_delete指定的处理方式。

例如删除作者id大于等于3的数据

result = models.Author.objects.get(id__gte=4).delete()

删除数据时一定要对你的表了如指掌,因为可能会牵连到很多其他数据。像在这个地方将这个作者删除了之后,那么这个作者对应的图书也将会被删除。

23. 切片操作:

有时候我们查找数据,有可能只需要其中的一部分。那么这时候可以使用切片操作来帮我们完成。QuerySet使用切片操作就跟列表使用切片操作是一样的。

# 获取1,2两条数据
  books = models.Book.objects.all()[1:3]
  for book in books:
    print(book)

以上这篇浅谈Django QuerySet对象(模型.objects)的常用方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
浅谈Python的垃圾回收机制
Dec 17 Python
Python 由字符串函数名得到对应的函数(实例讲解)
Aug 10 Python
python RabbitMQ 使用详细介绍(小结)
Nov 08 Python
详解一种用django_cache实现分布式锁的方式
Sep 01 Python
python列表插入append(), extend(), insert()用法详解
Sep 14 Python
使用tensorflow显示pb模型的所有网络结点方式
Jan 23 Python
python实现人脸签到系统
Apr 13 Python
Python中and和or如何使用
May 28 Python
Python如何避免文件同名产生覆盖
Jun 09 Python
python如何求圆的面积
Jul 01 Python
Kmeans均值聚类算法原理以及Python如何实现
Sep 26 Python
Python3.9新特性详解
Oct 10 Python
django使用F方法更新一个对象多个对象字段的实现
Mar 28 #Python
Django 拼接两个queryset 或是两个不可以相加的对象实例
Mar 28 #Python
使用Django实现把两个模型类的数据聚合在一起
Mar 28 #Python
使用python客户端访问impala的操作方式
Mar 28 #Python
python 安装impala包步骤
Mar 28 #Python
django 链接多个数据库 并使用原生sql实现
Mar 28 #Python
Django多数据库配置及逆向生成model教程
Mar 28 #Python
You might like
浅析十款PHP开发框架的对比
2013/07/05 PHP
php格式化时间戳显示友好的时间实现思路及代码
2014/10/23 PHP
php中convert_uuencode()与convert_uuencode函数用法实例
2014/11/22 PHP
PHP记录和读取JSON格式日志文件
2016/07/07 PHP
使用正则去除php代码中的注释方法
2016/11/03 PHP
php中get_object_vars()在数组的实例用法
2021/02/22 PHP
js jquery获取随机生成id的服务器控件的三种方法
2013/07/11 Javascript
js完美的div拖拽实例代码
2014/01/22 Javascript
封装好的一个万能检测表单的方法
2015/01/21 Javascript
理解JS绑定事件
2016/01/19 Javascript
JavaScript+html5 canvas绘制渐变区域完整实例
2016/01/26 Javascript
深入解析JavaScript中函数的Currying柯里化
2016/03/19 Javascript
Javascript必知必会(四)js类型转换
2016/06/08 Javascript
关于JavaScript中事件绑定的方法总结
2016/10/26 Javascript
利用JS实现文字的聚合动画效果
2017/01/22 Javascript
JavaScript实现两个select下拉框选项左移右移
2017/03/09 Javascript
AngularJS改变元素显示状态
2017/04/20 Javascript
node.js操作mongodb简单示例分享
2017/05/25 Javascript
Angular中的interceptors拦截器
2017/06/25 Javascript
vue.js项目打包上线的图文教程
2017/11/16 Javascript
vue-router动态设置页面title的实例讲解
2018/08/30 Javascript
Layui Form 自定义验证的实例代码
2019/09/14 Javascript
微信小程序点击列表跳转到对应详情页过程解析
2019/09/26 Javascript
[44:10]2018DOTA2亚洲邀请赛 4.5 淘汰赛 EG vs VP 第一场
2018/04/06 DOTA
[01:03:36]DOTA2-DPC中国联赛 正赛 VG vs Magma BO3 第二场 1月26日
2021/03/11 DOTA
python利用装饰器进行运算的实例分析
2015/08/04 Python
Python列表推导式与生成器用法分析
2018/08/02 Python
python 解决tqdm模块不能单行显示的问题
2020/02/19 Python
Html5 audio标签样式的修改
2016/01/28 HTML / CSS
小米旗下精品生活电商平台:小米有品
2018/12/18 全球购物
群众对十八届四中全会的期盼
2014/10/17 职场文书
党员教师群众路线个人整改措施
2014/10/28 职场文书
初中中等生评语
2014/12/29 职场文书
小学科学教学计划
2015/01/21 职场文书
创业计划书之香辣虾火锅
2019/09/23 职场文书
PyQt5爬取12306车票信息程序的实现
2021/05/14 Python