如何在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信号:
- 在你的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)
- 确保信号被正确加载:
如果你的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
相关产品推荐
相关产品推荐

