Reputation: 98
I have two models that represent a one-to-many relationship. The InterestRateCurve object can have many InterestRate objects. The issue is that when I have a function that creates two curves where each curve has one rate the rate of the second curve overwrites the rate of the first curve. So, I end up in the database with two rows for the curve and one row for the rate. When I execute a program that saves one curve and one rate and then execute a separate program that saves another curve with a rate then it's all fine.
I use Python 2.7 and Django 1.4.
MODELS:
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)
The following code works fine:
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()
This execution results in one curve and one rate saved.
In a seperate execution I run:
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()
This execution results in another curve and another rate saved.
However, the following execution does not work correctly:
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()
This results in two curves saved but only one rate saved. It seems that the second rate overwrites the first rate that was previously saved.
Upvotes: 2
Views: 539
Reputation: 4139
The problem is the specification of rates = []
as a class variable of InterestRateCurve
. Because of this definition, every object of InterestRateCurve
accesses the same list of rates.
After you created your first curve and rate in your example, InterestRateCurve.rates
contains the one created rate. Then you create a second curve and save it. InterestRateCurve.save()
is executed, jumps in the except
branch and does:
for rate in self.rates:
rate.curve = curve
rate.save()
Remember that self.rates
(= InterestRateCurve.rates
) contains your first rate? The loop sets the foreign key of this rate to your second curve and saves it. Now your first curve has no related rate anymore. The rate of your first curve belongs now to the second curve.
After that, you create a second rate with exactly the same attributes as your first rate. Since you specified in the InterestRate
model:
class Meta:
unique_together = ('type', 'term', 'numTerms', 'curve')
... there can only be one rate with exactly the same attributes. I'm not sure if the old one is deleted or the new one is not saved. However, the result is that you have only one rate object in the database, which belongs to your second curve.
Hope you understand what I mean. You should look at Python's pdb
module. That's a debugger which allows you to step through your code and is extremely helpful with such problems.
Upvotes: 1