I just started self learning Python and Django as a hobby recently, and have been trying to self develop a project which helps me in my construction business. I have developed certain functions in my project which give me the result I want, but is not the most ideal in terms of coding practises. However, I am just learning from scratch and modifying my code as I learn.
However, now I am stuck (maybe because my basic concept is only not correct?). Require help on how to proceed.
So here is my models.py
class FootingQuantity(models.Model):
member_name = models.CharField(max_length=8, unique=True)
--more fields hidden--
x_axis = models.FloatField()
y_axis = models.FloatField()
class BeamQuantity(models.Model):
work = models.ForeignKey(Work, default=1, on_delete=models.CASCADE)
member_name = models.CharField(max_length=8, unique=True)
location = models.ManyToManyField(FootingQuantity)
length = models.FloatField(blank=True)
breadth = models.FloatField()
height = models.FloatField()
-- more fields --
@property
def length_of_beam(self):
yy = self.location.all().values_list('y_axis', flat=True)
xx = self.location.all().values_list('x_axis', flat=True)
ylist = list(yy)
xlist = list(xx)
return abs(ylist[1] - ylist[0] + xlist[1] - xlist[0])
@property
def total_concrete_quantity(self):
return float(self.length) * float(self.breadth) * float(self.width)
def save(self, *args, **kwargs):
self.length = self.length_of_beam
self.total_quantity = self.total_concrete_quantity
super(BeamQuantity, self).save(*args, **kwargs)
def __float__(self):
return self.length, self.total_quantity
I want my model to accept ManytoManyRelation of 2 Footings selected and then calculate the length. The length will then multiply with height and width to give me the total quantity (There are other calculations as well but I am guessing they are all just crashing due to not getting length).
Currently, when I fill the Form or try to fill in details through the admin page and click on Save, I get a ValueError
ValueError - "<BeamQuantity: B5>" needs to have a value for field "id" before this many-to-many relationship can be used.
I think the ManytoManyField needs to save and then the calculation needs to run. Currently both are trying to occur simultaneously and hence the error. Please help.
Exactly, you need to create your BeamQuantity instance first, before calculating the length of beans. Leave those fields empty for a second.
To do that, I recommend you to let all the fields that require the many to many relationship to have a value, with blank=True
and null=True
.
So, I would rewrite the save method like this:
def save(self, *args, **kwargs):
if self.id: # it means the object was already created, so has an id.
self.length = self.length_of_beam
self.total_quantity = self.total_concrete_quantity
super(BeamQuantity, self).save(*args, **kwargs)
Then when you want to create a BeanQuantity, do:
bean_quantity = BeanQuantity.objects.create(**fields_you_want_here)
bean_quantity.save()
The second line will run the code in the save method, because now the object has an id.