本文介绍: 当前django没有提供能够批量创建更新方法,只有和以及,在实际业务中并不能满足我们需求。因此才会有了。


前言

当前django并没有提供能够批量创建更新方法,只有bulk_updatebulk_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 :字典,通用的筛选项,会传递ormfilter
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进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注