Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使Django模型实例与另一个模型实例关联_Python_Django - Fatal编程技术网

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

Python 如何使Django模型实例与另一个模型实例关联,python,django,Python,Django,我想将租金项下的金额增加到账目项下的金额。当用户在租金中键入金额时,应扣除或添加帐户中的金额,并应在支付时重置,或在未支付时保持不变 class Account(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=250) number = models.PositiveIntegerField(help_text="Account number

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

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)

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

  • 动态计算帐户的金额。您可以使用如下方法(或缓存的属性),而不是使用
    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']
    
    这种方法的优点是总是准确的:无论您如何创建和操作帐户和租金记录,这种方法都会返回正确的金额

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

  • 保存或删除租金时更新“帐户金额”字段:

    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()
    
    这种方法的优点是,金额存储在帐户记录中,因此不需要在每次需要时重新计算,只有在保存租金对象时才需要重新计算

    缺点是必须对Rent对象调用
    save()
    delete()
    。例如,您不能使用诸如
    Rent.objects.all().delete(…)
    Rent.objects.all().update(…)
    之类的查询集方法,因为不会调用您的自定义
    save()
    delete()

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

  • 收到后更新账户金额(感谢您的建议):

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

    与以前的解决方案相比的一个改进是,在删除查询集时也会发送
    post\u delete


  • 我建议使用信号(post_save)而不是覆盖租金节省方法。我认为更新将在不同的型号中进行,这特别干净。@user3375448:谢谢,非常好的建议!在第二个建议中,我是否为
    账户
    总和
    创建新实例?@tonde:您必须将
    更新金额
    方法添加到现有的
    账户
    类中。Django已经提供了
    Sum
    类,只需从Django.db导入它:
    。models import Sum
    。它回答了你的问题吗?
    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()