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

如何在DRF泛型类中重写删除方法并同步更新钱包金额

要解决删除Transaction后自动更新对应Wallet金额的问题,我给你两种实用方案,按需选择:

方案一:重写视图的destroy方法(仅API删除场景适用)

因为你用的是RetrieveUpdateDestroyAPIView,直接在视图类里重写删除逻辑,先更新钱包金额再删除交易:

from django.db import transaction
from rest_framework import generics

class TransactionDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Transaction.objects.all()
    serializer_class = TransactionSerializer
    name = 'transaction-detail'

    def destroy(self, request, *args, **kwargs):
        # 开启原子事务,保证更新钱包和删除交易的操作要么全成,要么全失败
        with transaction.atomic():
            instance = self.get_object()
            wallet = instance.wallet
            
            # 根据交易类型调整钱包金额
            # 这里假设你的KindOfTransaction模型有个`type`字段,值为'income'(收入)或'expense'(支出)
            # 实际使用时请根据你的模型字段/值修改判断逻辑
            if instance.kind.type == 'expense':
                # 删除支出交易,把金额加回钱包
                wallet.amount += instance.amount
            elif instance.kind.type == 'income':
                # 删除收入交易,从钱包里减去这笔金额
                wallet.amount -= instance.amount
            
            wallet.save()
            # 调用父类方法完成交易删除
            return super().destroy(request, *args, **kwargs)

方案二:使用Django信号(全场景通用,包括后台/admin删除)

如果希望不管通过什么途径删除交易(比如Django后台、shell脚本)都能自动更新钱包,推荐用Django的post_delete信号:

  1. 在你的app的models.py末尾添加信号处理函数:
from django.db.models.signals import post_delete
from django.dispatch import receiver
from django.db import transaction

@receiver(post_delete, sender=Transaction)
def update_wallet_after_transaction_delete(sender, instance, **kwargs):
    with transaction.atomic():
        wallet = instance.wallet
        # 同上面的金额调整逻辑,按需修改
        if instance.kind.type == 'expense':
            wallet.amount += instance.amount
        elif instance.kind.type == 'income':
            wallet.amount -= instance.amount
        wallet.save()

# 注册信号(用@receiver装饰器后这行可省略,保险起见可以加上)
post_delete.connect(update_wallet_after_transaction_delete, sender=Transaction)
  1. 确保信号被正确加载:
    如果你的app没有自定义AppConfig,需要修改apps.py:
from django.apps import AppConfig

class YourAppNameConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'your_app_name'  # 替换成你的app名称

    def ready(self):
        import your_app_name.models  # 导入models以加载信号

然后在settings.py的INSTALLED_APPS里替换成自定义的AppConfig路径:

INSTALLED_APPS = [
    # ...其他app
    'your_app_name.apps.YourAppNameConfig',
]

额外提醒:

  • 交易类型适配:请根据你KindOfTransaction模型的实际字段调整判断逻辑(比如如果用name字段存“收入”“支出”,就改成instance.kind.name == '支出')。
  • 金额精度问题:FloatField容易有精度误差,建议换成DecimalField处理金额:
    # Wallet模型的amount字段修改为:
    amount = models.DecimalField(max_digits=10, decimal_places=2, validators=[MinValueValidator(0.0)])
    # Transaction模型同理
    

内容的提问来源于stack exchange,提问作者Tu Le Thanh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 22:03:11