You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中创建active=True的ReferralCode时,如何将同用户其他实例设为False?

实现方案

你可以通过两种常用方式实现这个需求:重写模型的save方法,或者使用Django信号。

方法一:重写模型的save方法

直接在ReferralCode模型中重写save方法,在保存当前实例前处理其他活跃邀请码的状态,同时用事务保证操作的原子性,避免并发问题。

修改后的模型代码如下:

from django.db import models, transaction
from django.db.models import Q, UniqueConstraint
from django.contrib.auth.models import User
import random


class ReferralCode(models.Model):
    code_str = models.CharField(max_length=64,
                                primary_key=True,
                                default="".join(
                                    [chr(random.randrange(48, 123))
                                     for y in range(64)]))
    active = models.BooleanField(default=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE)

    class Meta:
        constraints = [
            UniqueConstraint(
                fields=["user", "active"],
                condition=Q(active=True),
                name="unique_active_code_for_user",
            )
        ]
    
    def save(self, *args, **kwargs):
        if self.active:
            # 开启事务,确保修改其他邀请码和保存当前实例的操作原子化
            with transaction.atomic():
                # 将当前用户的其他活跃邀请码设为非活跃
                ReferralCode.objects.filter(user=self.user, active=True).exclude(code_str=self.code_str).update(active=False)
        # 调用父类的save方法完成当前实例的保存
        super().save(*args, **kwargs)

这个方法会在创建新的活跃邀请码或者将现有邀请码设为活跃时,自动把该用户其他活跃的邀请码置为非活跃。

方法二:使用Django信号

如果希望逻辑和模型解耦,可以用pre_save信号来处理,在实例保存前触发状态修改逻辑:

# 在models.py或专门的signals.py文件中添加以下代码
from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.db import transaction
from .models import ReferralCode

@receiver(pre_save, sender=ReferralCode)
def deactivate_old_referral_codes(sender, instance, **kwargs):
    if instance.active:
        with transaction.atomic():
            # 排除当前实例,避免把自己也改成非活跃
            sender.objects.filter(user=instance.user, active=True).exclude(code_str=instance.code_str).update(active=False)

如果信号放在单独的signals.py中,需要在apps.py的ready方法中导入信号,确保信号被注册:

# apps.py
from django.apps import AppConfig

class YourAppConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'your_app_name'

    def ready(self):
        import your_app_name.signals

注意事项

  • 两种方法都使用了transaction.atomic(),确保修改其他邀请码和保存当前实例的操作要么全部成功,要么全部失败,避免出现数据不一致的情况。
  • 模型中已经存在的UniqueConstraint会在数据库层面保证每个用户最多有一个活跃邀请码,和代码逻辑形成双重保障。

内容的提问来源于stack exchange,提问作者Alexander Mirnyy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 08:43:33