浅谈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的迭代器和生成器使用实例
Jan 14 Python
Python max内置函数详细介绍
Nov 17 Python
python实时分析日志的一个小脚本分享
May 07 Python
Python字符串处理实现单词反转
Jun 14 Python
python 删除大文件中的某一行(最有效率的方法)
Aug 19 Python
python的Crypto模块实现AES加密实例代码
Jan 22 Python
python微信公众号之关键词自动回复
Jun 15 Python
Tensorflow使用支持向量机拟合线性回归
Sep 07 Python
python pygame实现方向键控制小球
May 17 Python
简单了解Django ContentType内置组件
Jul 23 Python
关于PyTorch源码解读之torchvision.models
Aug 17 Python
基于python全局设置id 自动化测试元素定位过程解析
Sep 04 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和ACCESS写聊天室(七)
2006/10/09 PHP
php获取qq用户昵称和在线状态(实例分析)
2013/10/27 PHP
php制作动态随机验证码
2015/02/12 PHP
php表单习惯用的正则表达式
2017/10/11 PHP
php的扩展写法总结
2019/05/14 PHP
北京奥运官方网站幻灯切换效果flash版打包下载
2008/01/30 Javascript
JS DOM 操作实现代码
2010/08/01 Javascript
js切换div css注意的细节
2012/12/10 Javascript
EXTjs4.0的store的findRecord的BUG演示代码
2013/06/08 Javascript
jQuery简单实现隐藏以及显示特效
2015/02/26 Javascript
JavaScript数组的定义及数字操作技巧
2016/06/06 Javascript
node.js与C语言 实现遍历文件夹下最大的文件,并输出路径,大小
2017/01/20 Javascript
webpack3之loader全解析
2017/10/26 Javascript
ES6下子组件调用父组件的方法(推荐)
2018/02/23 Javascript
深入理解Promise.all
2018/08/08 Javascript
vue elementUI tree树形控件获取父节点ID的实例
2018/09/12 Javascript
React Router V4使用指南(精讲)
2018/09/17 Javascript
微信小程序实现带缩略图轮播效果
2018/11/04 Javascript
JS图片懒加载的优点及实现原理
2020/01/10 Javascript
[43:32]2014 DOTA2华西杯精英邀请赛 5 25 LGD VS NewBee第一场
2014/05/26 DOTA
使用Python编写类UNIX系统的命令行工具的教程
2015/04/15 Python
python实现比较两段文本不同之处的方法
2015/05/30 Python
Python文件右键找不到IDLE打开项解决办法
2015/06/08 Python
Python命令启动Web服务器实例详解
2017/02/23 Python
Python Socket编程详细介绍
2017/03/23 Python
Python创建二维数组实例(关于list的一个小坑)
2017/11/07 Python
python安装模块如何通过setup.py安装(超简单)
2018/05/05 Python
python自动化生成IOS的图标
2018/11/13 Python
朴素贝叶斯Python实例及解析
2018/11/19 Python
python多线程同步实例教程
2019/08/11 Python
python模拟实现斗地主发牌
2020/01/07 Python
详解CSS3的opacity属性设置透明效果的用法
2016/05/09 HTML / CSS
世界上最大的高分辨率在线图片库:Alamy
2018/07/07 全球购物
个人典型事迹材料
2014/12/30 职场文书
禁毒主题班会教案
2015/08/14 职场文书
MySQL CHAR和VARCHAR该如何选择
2021/05/31 MySQL