Django批量创建与更新效率及常见字段陷阱详解
本文深入分析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() 与数据库事务的效率对比分析,旨在为开发者提供参考。希望这些信息能帮助大家优化代码,如有更多疑问,欢迎继续支持本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













