• 进入"运维那点事"后,希望您第一件事就是阅读“关于”栏目,仔细阅读“关于Ctrl+c问题”,不希望误会!

Django模型QuerySet API参考

Python框架 彭东稳 7年前 (2017-11-06) 28200次浏览 已收录 0个评论

一、QuerySet API介绍

一旦你建立好数据模型,Django会自动为你生成一套数据库抽象的API(QuerySet查询集方法),可以让你创建、检索、更新和删除对象。

Django使用一种直观的方式把数据库表中的数据表示成Python对象:一个模型类代表数据库中的一个表,一个模型类的实例代表这个数据库表中的一条特定的记录。使用关键字参数实例化模型实例来创建一个对象,然后调用save()把它保存到数据库中。

使用python manage.py shell命令可以进入到Python交互式窗口,跟你执行Python直接进入交互式窗口是不同的,前者会加载一些环境变量。

下面主要是通过一个简单的多人博客模型来学一些常见的各类查询,基本都是根据一些实用示例来的。

下面是一个简单的多人博客模型示例:

插入一些测试数据:

二、生成新QuerySet的方法

  • filter()

查询过滤

filter查询是指精确查询,而不是通配匹配查询。

  • exclude()

反向查询,指返回查询条件相反的对象。

  • order_by()

对结果集进行升序或降序,可指定需要排序的字段。

要随机排序可使用“?”

注意:order_by(‘?’)根据您使用的数据库后端,查询可能非常昂贵并且速度很慢。

  • reverse()

使用reverse()方法可以颠倒查询集元素返回的顺序,reverse()再次调用将恢复到正常方向的顺序。

  • values()

QuerySet当作为迭代器使用时,返回一个返回字典,而不是模型实例。

这些字典中的每一个都表示一个对象,其中的键与模型对象的属性名称相对应。

该values()方法采用可选的位置参数,*fields它指定SELECT应限制的字段名称。如果指定了字段,每个字典将仅包含您指定字段的字段键/值。如果不指定字段,则每个字典将包含数据库表中每个字段的键和值。

该values()方法还包含可选的关键字参数 **expressions,它们被传递给annotate():

  • values_list()

迭代时返回元组,每个元组都包含传入values_list()调用的相应字段或表达式的值,因此第一个项目是第一个字段等。例如:

如果只传入单个字段,则还可以传入 flat 参数,如果为True,这将意味着返回的结果是单值,而不是一元组。如下例子:

当有多个字段时 flat 传入错误。

将结果返回为列表有时候很有用,可能我们需要一个复杂的查询后返回列表,也可以使用filter先过滤出期望数据,然后再返回为列表。

你也可以通过named=True以获得结果为 namedtuple():

使用命名元组可能会使结果更具可读性,将结果转换为命名元组的代价很小。

如果你不传递任何值values_list(),它将按照声明的顺序返回模型中的所有字段。

  • distinct()

去重查询,消除查询结果中的重复行,返回一个新的QuerySet。

做完去重之后,如果想把结果封装成一个list,代码如下:

  • dates()

dates(field,kind,order =’ASC’)

返回一个表达式,该表达式表示QuerySet一个datetime.date对象列表。

field应该是DateField你模型的名称,kind应该是”year”,”month”或者”day”。datetime.date结果列表中的每个对象都被“截断”给定type。

“year” 返回该字段的所有不同年份值的列表。

“month” 返回该字段的所有不同年/月值的列表。

“day” 返回该字段的所有不同年/月/日值的列表。

order,默认为’ASC’,应该是’ASC’或者 ‘DESC’。这指定了如何排序结果。

  • datetimes()

datetimes(field_name,kind,order=’ASC’,tzinfo = None)

返回一个表达式,该表达式表示QuerySet一个datetime.datetime对象列表。

field_name应该是DateTimeField你模型的名称。

kind应该是”year”,”month”,”day”,”hour”,”minute”或”second”。datetime.datetime结果列表中的每个对象都被“截断”给定type。

order,默认为’ASC’,应该是’ASC’或者 ‘DESC’,这指定了如何排序结果。

tzinfo定义在截断之前将日期时间转换到的时区。事实上,根据使用的时区,给定的日期时间具有不同的表示形式。该参数必须是一个datetime.tzinfo对象。如果是None,Django使用当前时区。当它没有效果USE_TZ的 False。

  • raw()

在模型查询API不够用的情况下,你可以使用原始的SQL语句。Django提供两种方法使用原始SQL进行查询:一种是使用Manager.raw()方法,进行原始查询并返回模型实例;另一种是完全避开模型层,直接执行自定义的SQL语句。

raw()接受一个原始的SQL查询,执行它并返回一个 django.db.models.query.RawQuerySet实例。这个RawQuerySet实例可以像正常一样迭代QuerySet以提供对象实例。

传入变量的方式:

通过raw方法查询的结果是一个RawQuerySet对象,如果想取到所有的值可以这么做:

借助这个方法我们可以序列化一下这个对象:

使用方式:

  • 链式查询

可以在filter后跟exclude,如下:

也可以使用一些高级过滤,比如过滤以某某开头及某某结尾的名称:

  • 复杂查询Q filter()

Q filter()方法中的关键字参数查询都是一起进行“AND”的,如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象。

每个接受关键字参数的查询函数(如filter()、exclude()、get())都可以传递一个活多个Q对象作为位置(不带名的)参数。如果一个查询函数有多个Q对象参数,这些参数的逻辑关系为“AND”。查询函数可以混合使用Q对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q对象)都将“AND”在一起。但是,如果出现Q对象,它必须位于所有关键字参数的前面。例如:

使用 Q 还可以使用非逻辑,比如不能等于某个条件:

有些时候我们需要根据前端选择的不同字段进行构建查询条件,Q 也支持:

如果有多个逻辑表达式,也可以支持:

  • 保存ForeignKey和ManyToManyField字段

保存ManyToManyField,在创建Entry时不需要必须指定authors,它是一个ManyRelatedManager管理器,添加authors方式如下:

可以给e.authors对象指定列表,既然是管理器,所以也有很多方法可以使用,比如添加用户和查询用户:

当Entry有了之后,也可以快速创建authors,如下:

并且会自动把authors加入到Author表,如下:

  • 反向查询

如果模型有一个ForeignKey,那么该ForeignKey所指的模型实例可以通过一个管理器返回前一个模型的所有实例。默认情况下,这个管理器的名字为foo_set,其中foo是源模型的小写名称。该管理器返回的查询集可以用在过滤和操作上。

  • 跨关联关系查询

  • 引用模型字段查询

使用F可以获取模型字段值,常用来比较两个模型字段:

  • 限制返回对象

三、不返回QuerySet的方法

以下QuerySet方法结果集不返回QuerySet。这些方法不使用缓存。相反,他们每次查询都会调用数据库。

  • get()

返回匹配给定查找参数的对象,该参数应采用字段查找中描述的格式。

如果没有找到给定参数的对象,则引发异常。

  • create()

创建对象并将其全部保存在一个步骤中的便捷方法。从而:

是等同的。

  • get_or_create()

get_or_create(defaults=None, **kwargs)

一种方便的方法,get_or_create 方法尝试从数据库中获取基于给定 kwargs 的对象。如果没有找到匹配项则创建一个新的对象。

返回一个元组 (object, created),其中 object 是检索或创建的对象,created 是一个布尔值,指定是否创建了新对象。

这是代码编写的一种便捷,例如:

随着模型中字段数量的增加,这种模式变得相当不便。上面的例子可以使用get_or_create()像这样重写:

传递给 get_or_create () 的任何关键字参数 (除可选的”defaults”) 都将用于获取 get() 调用。如果找到一个对象,get_or_create() 将返回该对象的元组并进行 False。如果找到多个对象,get_or_create 将引发 MultipleObjectsReturned异常。如果找不到对象,get_or_create() 将实例化并创建一个新对象,返回新对象的元组和 True。将根据该算法粗略地创建新对象:

该 get_or_create() 方法和 create() 方法使用手动指定主键时的错误行为类似,如果需要创建对象并且数据库中已存在唯一key,则会引发一个IntegrityError异常。

  • update_or_create()

update_or_create(defaults=None, **kwargs)

一种方便的方法,update_or_create 方法尝试从数据库中获取基于给定 kwargs 的对象。如果找到匹配项,它将更新在默认字典中传递的字段。如果需要更新对象没有则创建一个新的。defaults 是用于更新对象的 (字段、值) 对的字典,默认值可以是 callables。

返回一个元组(object, created),其中 object 是创建或更新的对象,created是一个布尔值,指定是否创建了新对象。

这是代码编写的一种便捷,例如:

随着模型中字段数量的增加,这种模式变得相当不便。上面的例子可以使用update_or_create()像这样重写:

如上 get_or_create() 所述,如果在数据库级别不强制执行唯一性,则该方法容易出现竞争状况,这可能导致同时插入多行。像 get_or_create() 和 create(),如果你使用手动指定主键和需要创建一个对象,但主键在数据库中已存在,引发IntegrityError。

  • bulk_create()

bulk_create(objs, batch_size=None)

此方法以高效的方式将提供的对象列表插入数据库(通常只有1个查询,不管有多少个对象):

尽管如此,还是有一些注意事项:模型的save()方法不会被调用,它不适用于多表继承方案中的子模型,它不适用于多对多的关系。

  • count()

返回一个整数,表示与之匹配的数据库中QuerySet的对象数。count()方法从不引发异常。

  • latest()

根据给定的字段返回表中的最新对象。

该示例Entry根据该 pub_date 字段返回表中的最新内容:

  • first()

返回查询集匹配的第一个对象,或者为None表示没有匹配的对象。如果QuerySet没有定义的顺序,那么查询集由主键自动排序。这可能会影响聚合结果。

请注意,这是first()的一种方便方法,下面的代码示例等同于上面的示例:

  • last()

跟first()类似,但返回查询集中的最后一个对象。

  • in_bulk()

in_bulk(id_list = None,field_name =’pk’)

获取字段值(id_list)的列表以及field_name这些值,并返回一个字典,将每个值映射到具有给定字段值的对象的实例。如果id_list未提供,则返回查询集中的所有对象。field_name必须是唯一的字段,并且它默认为主键。

如果你传递in_bulk()一个空列表,你会得到一个空字典。

在Django 2.0中更改:该field_name参数已添加。

  • update()

对指定字段执行SQL更新查询,并返回匹配的行数(如果某些行已具有新值,则该行数可能不等于更新的行数)。

例如,要关闭2010年发布的所有博客条目的评论,你可以这样做:

你可以更新多个字段 – 对多少字段没有限制。例如,在这里我们更新comments_on和headline字段:

该update()方法立即应用。

  • delete()

对所有行执行SQL删除操作,QuerySet并返回删除的对象数和每个对象类型具有删除次数的字典。

delete()即时应用。例如,要删除特定博客中的所有条目:

  • aggregate()

返回通过计算得到的聚合值(平均值,总和等)的字典。

四、字段查找

字段查找是如何指定SQL WHERE子句的内容。它们被指定为QuerySet的filter(), exclude()或get()方法的关键字参数。使用__(双下划线)来查询。

exact:精确匹配,也是默认方式,iexact表示忽略大小写。

为了方便,当没有提供查找类型(如 Author.objects.get(id=1))时,查找类型被假定为exact。

还有一些常用类型,如下:

gt:大于。

gte:大于等于。

it:小于。

ite:小于等于。

isnull:为null。

contains:包含某某,icontains表示忽略大小写。

startswith:以某某开始,istartswith表示忽略大小写。

endswith:以某某结束,iendswith表示忽略大小写。

regex:正则匹配,区分大小写。

iregex:正则匹配,忽略大小写。

in:在给定的可迭代对象中,通常是一个列表,元组或查询集。

range:在某某范围之内。

date、year、month、week、day、second、hour、minute:时间日期类型。

官网:https://docs.djangoproject.com/en/2.0/ref/models/querysets


如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。
喜欢 (1)
[资助本站您就扫码 谢谢]
分享 (0)

您必须 登录 才能发表评论!