前言
当前django并没有提供能够批量创建或更新的方法,只有bulk_update
和bulk_create
以及create_or_update
,在实际业务中并不能满足我们的需求。因此才会有了bulk_update_or_create
一、代码实现
from utils import time_tools
from django.db import models
from django.db import transaction
# from bulk_update_or_create import BulkUpdateOrCreateQuerySet
class ExpandQuerySet(models.QuerySet):
"""
拓展querySet
"""
def bulk_update_or_create(self, common_keys, unique_key_name, unique_key_to_defaults, batch_size=200):
"""
common_keys: {field_name: field_value} 通用筛选条件
unique_key_name: field_name # 唯一字段
unique_key_to_defaults: {field_value: {field_name: field_value}} # 更新值
"""
with transaction.atomic(using=self.db, savepoint=False):
filter_kwargs = dict(common_keys)
filter_kwargs[f"{unique_key_name}__in"] = unique_key_to_defaults.keys()
existing_objs = {
getattr(obj, unique_key_name): obj
for obj in self.filter(**filter_kwargs).select_for_update()
}
# 批量创建
create_data = {
k: v for k, v in unique_key_to_defaults.items() if k not in existing_objs
}
for unique_key_value, obj in create_data.items():
obj[unique_key_name] = unique_key_value
obj.update(common_keys)
creates = [self.model(**obj_data) for obj_data in create_data.values()]
if creates:
self.bulk_create(creates, batch_size=batch_size)
# 如果使用了add_now来自动更新时间,update_fields必须包含此字段
# 因queryset.update不会自动更新时间,只有save会
update_fields = {"update_time"}
# 批量更新
updates = []
for key, obj in existing_objs.items():
for i in unique_key_to_defaults[key].items():
setattr(obj, i[0], i[1])
# 将所有要更新的字段都统计出来
update_fields.update(unique_key_to_defaults[key].keys())
updates.append(obj)
if existing_objs:
self.bulk_update(updates, update_fields, batch_size=batch_size)
return len(creates), len(updates)
def update(self, **kwargs):
if getattr(self.model, "update_time", None):
kwargs.update({"update_time": time_tools.now()})
return super().update(**kwargs)
class AbstractModel(models.Model):
objects: ExpandQuerySet = ExpandQuerySet.as_manager()
我们需要在我们的模型基类中重定义objects为我们的扩展类。
bulk_update_or_create共分为三步:1、查询数据库中包含当前数据的数据。2、调用父类批量创建bulk_create
方法,批量创建数据库中不存在的。3、调用父类批量更新bulk_update
方法,批量更新数据库中存在的。
ps:我们会在批量更新中定义一个update_fields = {"update_time"}
字段,
因为如果使用了add_now来自动更新时间,query.update 不会更新此此段,只有save中会,在save中对包含add_now的字段做了处理.
二、使用
bulk_create_or_update_dict = {}
for _ in self._contents:
if "url" in _:
unique = _["unique"]
permission_dict = {
Permission.name.field.attname: 1,
Permission.valid.field.attname: True,
Permission.desc.field.attname: 1,
Permission.level.field.attname: 1,
Permission.uri.field.attname: 1,
Permission.lambda_name.field.attname: 1,
Permission.action_name.field.attname: 1,
Permission.permission.field.attname: unique
}
bulk_create_or_update_dict[unique] = permission_dict
common_keys = {} # 通用筛选项
unique_key_name = Permission.permission.field.attname # 唯一值
unique_key_to_defaults = bulk_create_or_update_dict # 默认值
Permission.objects.using(PG_WRITE).bulk_update_or_create(common_keys, unique_key_name, unique_key_to_defaults)
common_keys :
字典,通用的筛选项,会传递到orm的filter中
unique_key_name :
字符串,唯一的字段的名称
unique_key_to_defaults :
字典,key为唯一的值,value为更新的数据
原文地址:https://blog.csdn.net/wmjf1/article/details/129534643
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_49521.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。