Reputation: 1201
I have two models
class Employee(models.Model):
name = models.CharField(max_length=20)
ID = models.IntegerField()
basic_salary = models.IntegerField()
total_leave = models.IntegerField(default = 14)
paid_leave = models.IntegerField(default = 0)
unpaid_leave = models.IntegerField(default = 0)
def __str__(self):
return self.name
class Leave_management(models.Model):
name = models.OnetoOneField(Employee,on_delete= models.CASCADE)
reason = models.CharField(max_length=50)
from = models.DateTimeField()
to = models.DateTimeField()
total_days = models.IntegerField()
def __str__(self):
return self.name
So,i want to minus 'total_days' of 'model-Leave_management' from 'total_leave' field of 'model-Employee'. And as per leaves taken i want to update 'paid_leave' and 'unpaid_leave' sections.
I can perform so if these two models would be one model(example below), But i dont know how to perform so in different models.
def save(self,*args,**kwargs):
if self.total_days<=self.total_leave:
self.total_leave -= self.total_days
self.unpaid_leave = 14 - self.total_leave
else:
self.total_days -= 14
self.paid_leaves = self.total_days
super(Model_name,self).save(*args,**kwargs)
` Please be guiding me.
Upvotes: 4
Views: 1529
Reputation: 477676
In fact your OneToOneField(..)
to an Employee
is not a name
. At the database level it will store values that correspond to primary keys of an Employee
, and in Django, name
will be a lazy fetch to the corresponding Employee
. Therefore I suggest to rename your function to (for example) employee
.
Another problem is that you define it as a OneToOneField
. That means that an Employee
has one Leave_management
. But based on the fields (reason
, from
, to
, etc.), it looks like an Employee
can have zero, one, or more Leave_management
s. So that means it is a ForeignKey
.
So our model looks like:
class Leave_management(models.Model):
employee = models.ForeignKey(Employee,on_delete= models.CASCADE)
reason = models.CharField(max_length=50)
from = models.DateTimeField()
to = models.DateTimeField()
total_days = models.IntegerField()
def __str__(self):
return self.employee.name
Like the __str__
function already suggests, we can obtain the name of the employee by querying self.employee
, and we can then fetch its .name
attribute.
But now the challenge is what to do when save a Leave_management
object. In that case the number of total_leave
and paid_leave
should be updated.
We first have to figure out the total number of total_days
that are stored in Leave_management
objects related to an Employee
, this is equal to:
(Leave_management.objects.filter(employee=some_employee)
.aggregate(totals=Sum('total_days'))['totals'] or 0
So we can then subtract this from 14
, and store the (possibly) remaining days in paid_leave
, like:
class Leave_management(models.Model):
# ...
def save(self, *args, **kwargs):
super(Leave_management, self).save(*args, **kwargs)
totals = (Leave_management.objects
.filter(employee=some_employee)
.aggregate(totals=Sum('total_days'))['totals'] or 0
employee = self.employee
unpaid = min(14, totals)
employee.total_leave = 14 - unpaid
employee.unpaid_leave = unpaid
employee.paid_leave = totals - unpaid
employee.save()
Note: typically we do not handle this by overriding the
.save(..)
function, but by using Django signals: triggers that can be implemented when certain objects are saved, etc. This especially should be used since the objects can be changed circumventing the.save(..)
function, and sometimes such objects might get deleted as well. So the above is not a good design decision.Even when we use signals, it is a good idea to frequently (for example once a day) recalculate the total leave, and update the corresponding
Employee
models.
Upvotes: 2