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

时间:2019-03-29 21:53:45

标签: django django-models django-forms

所以我有一个FK-d共享的交易模型。在“帐户”视图中,我具有这些交易的ModelFormset,并且可以通过遍历表单并将其保存来保存多个交易。

在我的交易记录的save()方法上,我尝试更新链接的Share上的余额。如果我保存一个事务,这将起作用,但是当我发布包含多个事务的ModelFormset时,每次我在Transaction save()覆盖中的 self.share.balance = self.share.balance + amt 行中(对于每个新交易),share.balance就是保存表单集中的任何先前交易之前的水平。

有人知道为什么以前保存的交易增加的股份余额额不会在以后的保存中进行吗(为什么只将最后一笔交易的数额添加到股份余额中)?

交易模型,该模型应更新父模型 Share

上的余额
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)

在视图中,我有一个交易表单集

#...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())

1 个答案:

答案 0 :(得分: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)