相关模型未在使用ModelFormset保存的模型的保存覆盖中更新

问题描述 投票:1回答:1

所以我的交易模型是FK-d到共享。在“帐户”视图中,我有这些事务的ModelFormset,我可以通过循环表单并保存它们来保存多个事务。

在我的Transaction的save()方法中,我尝试更新链接共享上的余额。如果我保存一个事务,但是当我使用多个事务发布我的ModelFormset时,每次我在事务保存()覆盖中触发self.share.balance = self.share.balance + amt行时(这适用于每个新事务) ),share.balance是在保存formset中的任何先前事务之前的状态。

有谁知道为什么后续保存不会从先前保存的交易中分配余额的额外金额(为什么只有最后一笔交易的金额会被添加到股票余额中)?

应更新父模型共享余额的交易模型

class Transaction(models.Model):
    share = models.ForeignKey(Share, on_delete=models.CASCADE, null=True, blank=True)
    account = models.ForeignKey(Account, on_delete=models.CASCADE, null=True, blank=True)

    db_cr = models.CharField(choices=DBCR, max_length=2)
    amt = models.DecimalField('Amount', max_digits=11, decimal_places=2)
    post_dt = models.DateTimeField('Post Time', null=True, blank=True)

    def save(self, *args, **kwargs):
        if not self.pk:

        ...

            if self.share:
                if self in self.share.transaction_set.all():
                    logging.error('Transaction %s already posted' % self.id)
                    return False

                amt = self.amt if self.db_cr == 'cr' else -self.amt
                self.share.balance = self.share.balance + amt
                self.share.save()

分享模型

class Share(models.Model):
    name = models.CharField(max_length=80)
    account = models.ForeignKey(Account, on_delete=models.CASCADE)
    definition = models.ForeignKey(ShareDef, on_delete=models.PROTECT)
    balance = models.DecimalField('Balance', max_digits=11, decimal_places=2, default=0)
    def __str__(self):
        return '%s %s %s %s'%(self.account,
                   self.name,
                   self.definition.sym_code,
                   self.balance )

    def save(self, *args, **kwargs):
        if not self.pk:

            if not self.name:
                self.name = self.definition.name
        super(Share, self).save(*args, **kwargs)

在视图中,我有一个Transaction formset

#...in view
TranFormSet = modelformset_factory(Transaction, exclude=('origin','ach_entry'), extra=1)

if request.method=='POST':
...
    tran_formset = TranFormSet(request.POST)
...
    if tran_formset.is_valid():
        for form in tran_formset:

            tran = form.save(commit=False)
            tran.account = account
            tran.origin = 'tt'
            tran.save()

else:

    #...following kind of weird because of how I'm setting querysets of ModelChoiceFields
    kwargs = {'account_instance': account}
    tran_formset = TranFormSet(queryset=Transaction.objects.none())
    tran_formset.form = (curry(TranForm, **kwargs))

形成

class TranForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        account_instance = kwargs.pop('account_instance', None)
        super(TranForm, self).__init__(*args, **kwargs)

            if account_instance:
                self.fields['share'].queryset = account_instance.share_set.all()

            if self.instance.pk:
                del self.fields['share']



    class Meta:
        model=Transaction
        exclude=['origin', 'ach_entry', 'account']


    post_dt = forms.DateTimeField(initial=datetime.date.today(), widget=forms.TextInput(attrs=
{
    'class': 'datepicker'
}))

    share = forms.ModelChoiceField(empty_label='---------', required=False, queryset=Share.objects.all())
django django-models django-forms
1个回答
1
投票

目前还不清楚是什么导致了这个问题,但在单个self.share.balance查询中执行update()的更新可能会有所帮助。这可以使用F expressions完成:

from django.db.models import F

class Transaction(models.Model):
    # ...

    def update_share_balance(self):
        if self.db_cr == "cr":
            amount = self.amt
        else:
            amount = -self.amt

        # By using the queryset update() method, we can perform the
        # change in a single query, without using a potentially old
        # value from `self.share.balance`
        return Share.objects.filter(id=self.share_id).update(
            balance=F("balance") + amount
        )

    def save(self, *args, **kwargs):
        if not self.pk:
            # ...
            if self.share:
                # ...
                self.update_share_balance()

        # Also, be sure to call the super().save() method at the end!
        super().save(*args, **kwargs)
© www.soinside.com 2019 - 2024. All rights reserved.