Django批量创建与更新效率及常见字段陷阱详解

键盘旁的猫
键盘旁的猫
发布时间:2026-10-13| 4人浏览过
原创

本文深入分析Django中bulk_create与update的性能差异,通过万级数据测试展示批量操作显著优势。同时详解default、auto_now等动态时间字段的设置陷阱,以及null与blank的区别,帮助开发者避免常见错误并提升数据库交互效率。

Django批量操作性能基准测试

为了直观展示不同操作方式的性能差异,以下测试以创建10000个对象为例进行基准比对。


# 用for循环挨个创建,共花费37秒
  for i in range(10000):
    name="String number %s"%i
    Record.objects.create(name=name)
 
# 用django事务只提交一次,共花费2.65秒
@transaction.commit_manually
def manual_transaction():
  for i in range(10000):
    name="String number %s"%i
    Record.objects.create(name=name)
  transaction.commit()
 
# 用bulk_create创建,共花费0.47秒
def builtin():
  insert_list =[]
  for i in range(10000):
    name="String number %s"%i
    insert_list.append(Record(name=name))
  Record.objects.bulk_create(insert_list)
 
# 用for循环挨个更新,共花费72秒:
def auto_transaction():
  for record inRecord.objects.all():
    record.name ="String without number"
    record.save()
 
# 用django事务只提交一次,共花费17秒
@transaction.commit_manually
def manual_transaction():
  for record inRecord.objects.all():
    record.name ="String without number"
    record.save()
  transaction.commit()
 
# 用update更新,共花费0.33秒
def builtin():
  Record.objects.all().update(name="String without number")

Django Model常见使用陷阱

在深入性能对比之前,有必要补充Django Model使用中容易遇到的几个关键陷阱,包括default=datetime.now与auto_now的区别、null与blank的语义差异、save与update的执行逻辑,以及bulk_create的特殊行为。

动态默认时间的设置方式

一、Django中设置字段动态默认时间的四种常见方式:


from django.db import models
from datetime import datetime

class User(models.Model):
  id = models.BigAutoField('主键', primary_key=True)
 
  name = models.CharField('名字', max_length=20, db_index=True, default='')
 
  create_time_one = models.DateTimeField('创建时间', default=datetime.now())
  update_time_one = models.DateTimeField('更新时间', default=datetime.now)
 
  create_time_tow = models.DateTimeField('创建时间', auto_now_add=True)
  update_time_tow = models.DateTimeField('更新时间', auto_now=True)

1. 使用 default=datetime.now()

当Model每次初始化时,该字段会自动被赋予初始化时刻的时间值。

2. 使用 default=datetime.now

注意这里没有括号。Model在每次执行新增或修改操作时,会自动将该字段更新为当前操作时间。即便设置了此默认值,开发者仍可通过ORM手动修改该字段。

3. 使用 auto_now_add=True

该参数默认为False。若设置为True,Model在每次执行新增操作时,会自动将该字段设置为当前时间。一旦设为True,便无法通过ORM手动修改该字段,即使手动赋值也会被系统覆盖。

4. 使用 auto_now=True

该参数默认为False。若设置为True,Model在每次执行新增或修改操作时,都会自动将该字段更新为当前时间。同样,设为True后无法通过ORM手动修改,手动填充的值也会被覆盖。

5. 关键注意事项

除非你的业务逻辑确实需要记录项目启动时间,否则使用 default=datetime.now() 是错误的写法,这会导致所有记录获得相同的初始化时间,而非预期的动态时间。

在使用 User.objects.update 方法时,设置 default=datetime.now 和 auto_now=True 均不会生效。由于 auto_now=True 的字段禁止手动修改,此时若需更新数据,只能使用 save 方法。这种方式在处理多条数据更新时显得不够友好。

因此,若需设置动态默认时间字段,推荐采用 default=datetime.now(无括号)或 auto_now_add=True 来实现。

null与blank的区别

二、null=True 和 blank=True 的区别

1. null 针对数据库层面:若设置 null=True,表示数据库中的该字段允许存储空值(NULL)。

2. blank 针对表单验证层面:若设置 blank=True,表示在表单填写该字段时允许留空。

在MySQL中,空字符串不占用存储空间,而NULL值占用空间且会降低索引效率。因此,从性能角度考虑,不建议使用 null=True,更推荐使用 default='' 来替代。

save与bulk_create对比

三、save 和 bulk_create 的区别

1. 使用 save 方法:


names = ['张三', '李四']
for name in names:
  user = User(name=name)
  user.save()
  print(user.id) # 此时user对象有id的值

2. 使用 bulk_create 方法:


names = ['张三', '李四']
users = [User(name=name) for name in names]
users = User.objects.bulk_create(users)
print([user.id for user in users]) # 此时user对象没有id的值

bulk_create 的优点:

在批量操作场景下,它仅与数据库进行一次交互,从而显著提升执行效率。

bulk_create 的缺点:

对于设置了自增主键的字段,返回值列表中不会包含该字段的值。例如在上述示例2中,返回的 user 对象不包含 id 值。

对于设置了动态默认时间的字段(如 auto_now=True),同一批处理的记录中,该字段的时间戳将完全相同。

综合应用示例

四、上述知识点的实际应用示例

1. 定义模型:


from django.db import models
from datetime import datetime
 
class User(models.Model):
  id = models.BigAutoField('主键', primary_key=True)
  name = models.CharField('名字', max_length=20, db_index=True, blank=False, default='')
  create_time = models.DateTimeField('创建时间', auto_now_add=True)
  update_time = models.DateTimeField('更新时间', default=datetime.now)

2. 插入数据:


# 方法一
names = ['张三', '李四']
users = [User(name=name) for name in names]
users = User.objects.bulk_create(users)
 
# 方法二
names = ['张三', '李四']
users = [User(name=name) for name in names]
[user.save() for user in users]

3. 修改数据:


# 方法一
names = ['张三', '李四']
User.objects.filter(name__in=names).update(name='changed', update_time=datetime.now()) # 这里必须显式对update_time赋值
 
# 方法二
names = ['张三', '李四']
users = User.objects.filter(name__in=names)
for use in users:
  user.name = 'changed'
  user.save() # 这里会自动更新update_time,但是多次save效率低

以上内容关于 Django bulk_create()、update() 与数据库事务的效率对比分析,旨在为开发者提供参考。希望这些信息能帮助大家优化代码,如有更多疑问,欢迎继续支持本站。

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

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