Django中QuerySet与Model对象的操作陷阱及正确用法解析

叶初
叶初
发布时间:2026-10-12| 5人浏览过
原创

本文深入解析Django中filter()返回的QuerySet与get()返回的Model对象在数据操作上的核心差异。重点指出直接修改QuerySet无法同步至数据库的原因,并提供通过first()或[0]获取实例后调用save()的正确更新方案。同时对比filter与get在空值处理、类型匹配及批量更新时的行为差异,帮助开发者避免常见ORM使用错误。

首先通过代码示例进行说明。

观察以下代码片段:

示例1:

  message = Message.objects.filter(pk=message_id2)
 
   message[0].id = message_id2
   message[0].content = content2
   message[0].message_type = message_type2
print(message[0].id)
print(message[0].content)
 
   message[0].save()

上述代码能够正常从QuerySet中读取数据并打印,运行无误。然而,这种操作无法将修改后的数据同步回数据库。

(1)调用all()方法返回的是QuerySet对象。此时程序并未真正在数据库中执行SQL查询,但该对象支持迭代操作,因此可以通过for循环遍历获取数据。

假设存在一个Book表,包含bookname和booknum两个字段,探讨如何利用Objects.all()方法获取这两个字段的值。

(2)filter()方法同样返回QuerySet对象,其行为与all()类似。区别在于,all()用于查询所有数据,而filter()常用于表示“等于”条件的查询,exclude()则用于表示“不等于”。

(3)get()方法返回的是具体的Model对象(注意:原文称类型为列表,实际应为单个模型实例,此处保留原意但修正表述以符合技术事实,即直接获取数据)。使用get方法会立即执行SQL语句从数据库获取数据。

观察一个QuerySet对象的示例:

message = Message.objects.filter(pk=message_id2) message[0].content

虽然可以读取到QuerySet中的数据,但对QuerySet对象进行修改后,这些更改无法保存到数据库。

在示例1中,不要尝试通过message.save()来同步数据到数据库,因为QuerySet对象本身不存在save()方法。

正确的写法如下:

若要将数据同步到数据库中,必须使用具体的模型对象进行数据同步操作。

示例2:

message = Message.objects.filter(pk=message_id2).first()
 
   message.id = message_id2
   message.content = content2
   message.message_type = message_type2
   message.save()

补充知识:关于Django中filter和get的个人使用体会。

开发环境配置:Ubuntu 16.04 + Django 1.11.9 + Python 2.7。

filter返回的是QuerySet对象:

filter返回的是QuerySet,支持切片和遍历操作;而get不支持,因为get旨在获取唯一存在的数据,若不存在或存在多条记录,get会抛出异常。

当没有符合条件的记录时:

get方法会报错。

Book matching query does not exist.

而filter则返回一个空的QuerySet列表,不会报错。

<QuerySet []>`

代码可以继续往下执行。

判断filter是否有值时:

book_info = Book.objects.filter(id=book_id, request_type=2)

queryset.exists() if book_info.exists():

queryset.count==0:
if queryset.count>0:
  pass
else:
  pass
if queryset:
if queryset:
  pass
else:
  pass

filter在某些情况下也会报错:

当filter字段类型为int时,若传入的参数却是str类型,会引发报错:

invalid literal for int() with base 10: 'Yu'

使用get时,若遇到相同情况,错误信息与上述filter报错一致。

当filter字段存在,但filter不到对应值时:

输出结果为:<QuerySet []>

当结果为空时,自然不能通过[0]进行取值操作。

在使用filter作为过滤条件更新数据时:

Book.objects.filter(id=book_id, request_type=2).order_by("-time")[0].update(result=note)

该操作会报错:

'Book' object has no attribute 'update'

使用filter不能进行部分更新,必须更新所有符合条件的记录(注:此处原文逻辑有误,update是QuerySet方法,但报错是因为调用了[0]后的Model对象无update方法,下文修正为正确逻辑)。

但是可以使用[0]获取符合过滤条件的第一个值。

解决办法是使用save()方法:

book_info = Book.objects.filter(id=book_id, request_type=2).order_by("-time")[0]
book_info.result = note
book_info.save()

filter字段后常见的

这里是双下划线,即__。

__gt 大于 __gte 大于等于 __lt 小于 __lte 小于等于 __contains 包含 __icontains 包含 忽略大小写 __startswith 以...开头 __istartswith 以...开头 忽略大小写 __endswith 以...结尾 __iendswith 以...结尾,忽略大小写

以上关于Django中使用filter()(即对QuerySet操作)时遇到的坑的分享就是全部内容,希望能给大家一个参考,也希望大家多多支持本站。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。