Django数据库性能优化:深入解析save与update的区别及commit=False用法

栗子
栗子
发布时间:2026-10-13| 4人浏览过
原创

本文深入解析Django中单条记录保存的两种主要方式:save()与update()。通过对比底层生成的SQL语句,指出update在批量或单条更新时具有更高的执行效率。此外,文章详细讲解了save(commit=False)方法在处理非表单字段(如author)时的应用场景,以及配合save_m2m()处理多对多关系的完整流程,帮助开发者写出更高效的Django代码。

Django数据库操作性能分析

Python Web框架Django凭借丰富的内置功能备受开发者青睐,其ORM模型层极大简化了数据库交互。然而,这种高层封装也意味着开发者需要深入理解其底层机制,才能有效优化数据库操作性能。明确Django在后台实际执行的SQL语句,是提升应用性能的关键前提。

save与update方法对比

在进行数据更新操作时,针对单条记录,开发者通常面临两种选择:使用模型实例的save()方法,或者使用QuerySet的update()方法。

为了直观对比这两种方式生成的SQL差异,可以在Django项目的settings.py配置文件中,将日志级别设置为DEBUG模式。这样在控制台或日志文件中即可清晰查看每次数据库操作所对应的具体SQL语句。

假设数据库中有一张名为Example的表,用于存储相关数据。

首先演示使用save()方法的场景。


k = Example.objects.get(id=481)
k.total_calories = 12
k.save()

执行上述save()操作后,系统实际生成的SQL语句如下所示:

SELECT (1) AS `a` FROM `Example` WHERE ` Example`.`id` = 481 LIMIT 1; args=(481,) UPDATE `Example` SET `user_id` = asdfasdf, `event_id` = -1, `join_type` = 0, `name` = , `phon e` = , `email` = , `company_name` = , `address` = , `if_type` = 0, `code` = , `l ocation` = , `total_days` = 0, `total_length` = 0, `total_calories` = 12, `comme nts` = , `reserved_1` = , `reserved_2` = , `reserved_3` = , `reserved_4` = , `re served_5` = , `create_datetime` = 2015-02-02 17:43:53 WHERE `Example` .`id` = 481 ; args=(u'asdfasdf', -1, 0, u'', u'', u' ', u'', u'', 0, u'', u'', 0, 0, 12, u'', u'', u'', u'', u'', u'', u'2015-02-02 1 7:43:53', 481)

从上述SQL可以看出,save()方法的工作流程是:首先执行SELECT查询获取该条记录,然后在save()提交时,将Example表中所有字段都进行SET赋值更新。这意味着即使只修改了一个字段,所有字段也会被重新写入数据库。

接下来演示使用update()方法的场景。

示例代码为:Example.objects.filter(id=481).update(total_calories = 10)

该操作直接生成的SQL语句是:


UPDATE `Example` SET `total_calories` = 1
0 WHERE (`Example`.`user_id` = asdfasdf
AND `Example`.`id` = 481 ); args=(10, u'asdfasdf', 481)

这条SQL语句结构简洁,仅更新指定字段,其执行速度明显优于使用save()方法。

从SQL执行的效率来看,使用update()方式在性能上优于save()方式。

从适用场景分析,update()方法更适合用于批量数据更新操作;而save()方法则更适合且仅适合用于单条记录的完整数据更新操作。

在使用Django数据模型进行数据库操作时,深入理解这些底层的SQL执行逻辑对于编写高效代码至关重要。

save(commit=False)与save_m2m实战

补充知识:如何正确理解Django的save(commit=False)方法和save_m2m()方法

何时使用save(commit=False)方法,以及save_m2m()方法的使用时机和具体用法,是掌握Django表单(forms)进阶技巧的必备知识。接下来我们将详细探讨。

save(commit=False)的应用场景

何时应该使用save(commit=False)方法?

Stackoverflow上有一个非常精炼的解释。英文原文如下,这里提供中文翻译:

That's useful when you get most of your model data from a form, but need to populate some null=False fields with non-form data. Saving with commit=False gets you a model object, then you can add your extra data and save it.

当你通过表单获取模型数据,但需要为模型中定义为null=False的字段添加一些非表单来源的数据时,该方法非常有用。如果指定commit=False,save方法不会立即将数据存储到数据库,而是返回一个当前的模型对象实例。此时,你可以添加表单之外的额外数据,最后再统一存储到数据库中。

save(commit=False)方法的实际应用案例。

下面通过一个实际案例进行说明。我们创建了一个名为Article的文章模型,包含title、body和author等多个字段,其中author字段被设置为非空(null=False)。基于Article模型创建了一个ArticleForm表单,允许用户发表新文章,但我们故意在表单中排除了author字段,因为不希望用户直接编辑作者信息。

最终用户提交的表单数据中必然不包含author字段,如果直接存入数据库会因违反非空约束而出错。因此,我们先通过article = form.save(commit=False)创建article实例,此时Django暂不发送数据到数据库。等待我们将author字段添加好后,再调用save()将数据一起存储到数据库中。

以下是视图文件views.py中的相关代码,重点在于ArticleForm的定义和article_create视图函数的实现。


from .models import Article
from django.forms import ModelForm
from django.http import HttpResponseRedirect
from django.shortcuts import render

class ArticleForm(ModelForm):
 class Meta:
  model = Article
  exclude = ['author']


def article_create(request):
 if request.method == 'POST':
  form = ArticleForm(request.POST)
  if form.is_valid():
   article = form.save(commit=False)
   # commit=False告诉Django先不提交到数据库.
   article.author = request.user # 添加额外数据
   article.save() # 发送到数据库

   return HttpResponseRedirect("/blog/")
 else:
  form = ArticleForm()
 return render(request, 'blog/article_create_form.html', {'form': form})

如果你使用Django自带的基于类的视图(CBV),可以通过重写form_valid方法完成相同的操作。具体代码如下。


from django.views.generic.edit import CreateView
from .models import Article
from django.forms import ModelForm


# Create your views here.
class ArticleForm(ModelForm):
 class Meta:
  model = Article
  exclude = ['author']

  
class ArticleCreateView(CreateView):
 model = Article
 form_class = ArticleForm
 template_name = 'blog/article_create_form.html'

 # Associate form.instance.user with self.request.user
 def form_valid(self, form):
  form.instance.author = self.request.user
  return super().form_valid(form)

save_m2m方法的使用条件

何时使用save_m2m方法以及如何正确使用?

save_m2m方法专门用于存储多对多(Many-to-Many)关系。当同时满足以下两个条件时,必须使用此方法:如果直接使用save()或form_valid()方法,通常可以直接存储多对多关系,无需额外调用save_m2m。

你使用了save(commit=False)方法。

你的模型中包含多对多关系字段(例如tags)。

假设我们的文章模型中包含tags这个多对多字段,我们的article_create方法需要增加一行代码来保存这些关系。


def article_create(request):
 if request.method == 'POST':
  form = ArticleForm(request.POST)
  if form.is_valid():
   article = form.save(commit=False)
   # commit=False tells Django that "Don't send this to database yet.

   article.author = request.user # Set the user object here
   article.save() # Now you can send it to DB
   form.save_m2m()

   return HttpResponseRedirect("/blog/")
 else:
  form = ArticleForm()
 return render(request, 'blog/article_create_form.html', {'form': form})

以上关于Django数据库操作中save与update的使用解析及commit=False的补充知识就是全部内容,希望能为大家提供有价值的参考,也希望大家多多支持本站。

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

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 算法库。