Skip to main content
 首页 » 编程设计

python之在 Django 中,保存两个对象时,外键关系无法正确保存

2025年05月04日33lonelyxmas

我有两个代表一对多关系的模型。 InterestRateCurve 对象可以有许多 InterestRate 对象。 问题是,当我有一个创建两条曲线的函数时,每条曲线都有一个速率,第二条曲线的速率会覆盖第一条曲线的速率。所以,我最终在数据库中有两行曲线和一行利率。 当我执行一个保存一条曲线和一个速率的程序,然后执行一个单独的程序来保存另一条曲线和一个速率时,一切都很好。

我使用 Python 2.7 和 Django 1.4。

模型:

class InterestRate(models.Model): 
    type = models.CharField(max_length=20) 
    term = modelFields.tgTimePeriodField(max_length=20) 
    numTerms = models.IntegerField() 
    mid = models.FloatField() 
    curve = models.ForeignKey('InterestRateCurve') 
 
    class Meta: 
        unique_together = ('type', 'term', 'numTerms', 'curve') 
 
    def __unicode__(self): 
        return "%s/%s/%s/%s" % (self.type, self.term, self.numTerms, self.curve) 
 
    def __str__(self): 
        return "%s/%s/%s/%s/%s" % (self.type, self.term, self.numTerms, self.mid, self.curve) 
 
 
class InterestRateCurve(models.Model): 
    ccy = modelFields.tgCurrencyField(max_length=20) 
    index = models.CharField(max_length=20) 
    term = modelFields.tgTimePeriodField(max_length=20) 
    numTerms = models.IntegerField() 
    asOf = modelFields.tgDateField() 
    cvid = models.CharField(max_length=20, blank=True, default='') 
    #rates needs to be explicitly maintained inside class for convenience 
    rates = [] 
 
    class Meta: 
        unique_together = ('ccy', 'index', 'term', 'numTerms', 'asOf', 'cvid') 
 
    def __unicode__(self): 
        return "%s/%s/%s/%s/%s/%s" % (self.ccy, self.index, self.term, \ 
                                      self.numTerms, self.asOf, self.cvid) 
 
    def save(self): 
        try: 
            curve = InterestRateCurve.objects.get(ccy=self.ccy, index=self.index,\ 
                                                  term=self.term, numTerms=self.numTerms,\ 
                                                  asOf=self.asOf, cvid=self.cvid) 
            #Delete all rates before saving the new rates 
            oldRates = curve.interestrate_set.all() 
            for oldRate in oldRates: 
                oldRate.delete() 
            for rate in self.rates: 
                rate.curve = curve 
                rate.save() 
        except InterestRateCurve.DoesNotExist: 
            super(InterestRateCurve, self).save() 
            curve = InterestRateCurve.objects.get(ccy=self.ccy, index=self.index,\ 
                                                  term=self.term, numTerms=self.numTerms,\ 
                                                  asOf=self.asOf, cvid=self.cvid) 
            for rate in self.rates: 
                rate.curve = curve 
                rate.save() 
 
    def addRate(self, rate): 
        rate.curve = self 
        exists = False 
        for r in self.rates: 
            if r.type == rate.type: 
                if r.term == rate.term: 
                    if r.numTerms == rate.numTerms: 
                        exists = True 
                        continue 
        if exists == False: 
            self.rates.append(rate) 

下面的代码工作正常:

        date = tgDate(month=9,day=12,year=2011) 
        curve = InterestRateCurve(ccy='USD', index='LIBOR', term='M',  
                                  numTerms=3, asOf=self.asOf, cvid='TESTSAVE2CURVES') 
        curve.save() 
        curve = InterestRateCurve.objects.get(ccy='USD', index='LIBOR', term='M',  
                                              numTerms=3, asOf=date, cvid='TESTSAVE2CURVES') 
        rate = InterestRate(term='M', numTerms=1, type='Deposit', mid=0.01, curve=curve) 
        curve.addRate(rate) 
        curve.save() 

此执行结果保存了一条曲线和一个速率。

在单独的执行中我运行:

        date = tgDate(month=9,day=13,year=2011) #DATE DIFFERS 
        curve = InterestRateCurve(ccy='USD', index='LIBOR', term='M',  
                                   numTerms=3, asOf=date, cvid='TESTSAVE2CURVES') 
        curve.save() 
        curve = InterestRateCurve.objects.get(ccy='USD', index='LIBOR', term='M',  
                                              numTerms=3, asOf=date, cvid='TESTSAVE2CURVES') 
        rate = InterestRate(term='M', numTerms=1, type='Deposit', mid=0.01) 
        curve.addRate(rate) 
        curve.save() 

此执行会产生另一条曲线并保存另一条速率。

但是,下面的执行不能正常工作:

    def testSave2Curves(self): 
        date = tgDate(month=9,day=12,year=2011) 
        curve = InterestRateCurve(ccy='USD', index='LIBOR', term='M',  
                                  numTerms=3, asOf=date, cvid='TESTSAVE2CURVES') 
        curve.save() 
        curve = InterestRateCurve.objects.get(ccy='USD', index='LIBOR', term='M',  
                                              numTerms=3, asOf=date, cvid='TESTSAVE2CURVES') 
        rate = InterestRate(term='M', numTerms=1, type='Deposit', mid=0.01, curve=curve) 
        curve.addRate(rate) 
        curve.save() 
        date1 = tgDate(month=9,day=13,year=2011) 
        curve1 = InterestRateCurve(ccy='USD', index='LIBOR', term='M',  
                                   numTerms=3, asOf=date1, cvid='TESTSAVE2CURVES') 
        curve1.save() 
        curve1 = InterestRateCurve.objects.get(ccy='USD', index='LIBOR', term='M',  
                                               numTerms=3, asOf=date1, cvid='TESTSAVE2CURVES') 
        rate1 = InterestRate(term='M', numTerms=1, type='Deposit', mid=0.01) 
        curve1.addRate(rate1) 
        curve1.save() 

这导致保存了两条曲线,但只保存了一个速率。似乎第二个费率覆盖了之前保存的第一个费率。

请您参考如下方法:

问题是将 rates = [] 指定为 InterestRateCurve 的类变量。由于这个定义,InterestRateCurve 的每个对象都访问相同的利率列表。

在示例中创建第一条曲线和利率后,InterestRateCurve.rates 包含创建的利率。然后创建第二条曲线并保存。 InterestRateCurve.save() 被执行,跳转到 except 分支并执行:

for rate in self.rates: 
    rate.curve = curve 
    rate.save() 

还记得 self.rates (= InterestRateCurve.rates) 包含您的第一利率吗?循环将此速率的外键设置为您的第二条曲线并保存。现在你的第一条曲线不再有相关率。您的第一条曲线的速率现在属于第二条曲线。

之后,您将创建一个与第一费率具有完全相同属性的第二费率。由于您在 InterestRate 模型中指定:

class Meta: 
    unique_together = ('type', 'term', 'numTerms', 'curve') 

...只能有一个速率具有完全相同的属性。我不确定是旧的被删除了还是新的没有保存。然而,结果是您在数据库中只有一个速率对象,属于您的第二条曲线。

希望你明白我的意思。您应该查看 Python 的 pdb 模块。这是一个调试器,可让您单步执行代码,对解决此类问题非常有帮助。