From 78a781290d5720979fc47e2929c7e9e914aed7c2 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 9 Jan 2026 16:53:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20base=20=E6=B7=BB=E5=8A=A0locked=5Fget?= =?UTF-8?q?=5For=5Fcreate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/utils/models.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/apps/utils/models.py b/apps/utils/models.py index 1e715a9..bdc4a48 100755 --- a/apps/utils/models.py +++ b/apps/utils/models.py @@ -150,7 +150,32 @@ class BaseModel(models.Model): raise time.sleep(0.1 * (attempt + 1)) - + + @classmethod + def locked_get_or_create(cls, defaults: dict, **kwargs): + """ + 仅用于事务内 + 并发安全的 get_or_create + """ + if not connection.in_atomic_block: + raise RuntimeError("locked_get_or_create 必须在事务中调用") + + defaults = defaults or {} + + qs = cls.objects.select_for_update().filter(**kwargs) + + cnt = qs.count() + if cnt > 1: + raise RuntimeError( + f"{cls.__name__} 数据异常:定位条件 {kwargs} 命中 {cnt} 条" + ) + + if cnt == 1: + return qs.get(), False + + obj = cls.objects.create(**kwargs, **defaults) + return obj, True + def handle_parent(self): pass