如何使Django模型实例与另一个模型实例相关联

2024-04-26 14:55:51 发布

您现在位置:Python中文网/ 问答频道 /正文

我想让租金下的金额在账户下的金额上增加。当用户在租金中键入金额时,应扣除或添加帐户中的金额,并应在支付时重置,或在未支付时保持不变

class Account(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=250)
    number = models.PositiveIntegerField(help_text="Account number", unique=True, blank=True, null=False)
    currency = models.CharField(max_length=3, choices=ALLOWED_CURRENCIES)
    creation_date = models.DateTimeField(auto_now_add=True)
    amount = models.DecimalField(max_digits=MONEY_MAX_DIGITS, decimal_places=MONEY_DECIMAL_PLACES, help_text="Latest"                                                                                                  "balance", default=0, blank=False, null=True)

class Rent(models.Model):
    source = models.ForeignKey(Account, on_delete=models.CASCADE, verbose_name="Account holder.")
    amount = models.DecimalField(max_digits=MONEY_MAX_DIGITS, decimal_places=MONEY_DECIMAL_PLACES)
    date = models.DateTimeField(auto_now_add=True)

Tags: textnametruenumbermodelmodelshelpaccount
1条回答
网友
1楼 · 发布于 2024-04-26 14:55:51

您可以使用以下三种策略之一:

  1. 动态计算账户金额。不使用amount字段,您可以使用如下方法(或者缓存属性):

    from django.db.models import Sum
    
    class Account(models.Model):
    
        # ...
    
        def amount(self):
            result = self.rent_set.all().aggregate(
                total_amount=Sum('amount'))
            return result['total_amount']
    

    这种方法的优点是总是精确的:无论您如何创建和操作帐户和租金记录,这种方法都将始终返回正确的金额

    它的缺点是每次调用时都会发出一个查询。这将对性能产生影响

  2. 保存或删除租金时更新帐户金额字段:

    from django.db.models import Sum
    
    class Account(models.Model):
    
        # ...
    
        def update_amount(self):
            result = self.rent_set.all().aggregate(
                total_amount=Sum('amount'))
            self.amount = result['total_amount']
    
    class Rent(models.Model):
    
        # ...
    
        def save(self, *args, **kwargs):
            super().save(*args, **kwargs)
            self.account.update_amount()
            self.account.save()
    
        def delete(self, *args, **kwargs):
            account = self.account
            super().delete(*args, **kwargs)
            account.update_amount()
            account.save()
    

    这种方法的优点是金额存储在帐户记录中,因此不需要每次需要时都重新计算,只有在保存租金对象时才需要重新计算

    缺点是您必须调用租用对象上的save()delete()。例如,您不能使用像Rent.objects.all().delete(...)Rent.objects.all().update(...)这样的queryset方法,因为您的自定义save()delete()将不会被调用

    另一个问题是,如果您在数据库级别编辑/删除租金记录,而不经过自定义代码,则金额将不会更新

  3. 收到^{}/^{} signals后更新账户金额(感谢user3375448的建议):

    from django.db.models.signals import post_save, post_delete
    from django.dispatch import receiver
    
    @receiver(post_save, sender=Rent)
    @receiver(post_delete, sender=Rent)
    def my_handler(sender, instance, **kwargs):
        instance.account.update_amount()
    

    这与前面的解决方案基本相同,并且有着相同的优点和缺点

    与前面的解决方案相比的一个改进是,在删除queryset时也会发送post_delete

相关问题 更多 >