How to perform multiplication in django model? - django

This is my model:
class Purchase(models.Model):
Quantity = models.PositiveIntegerField()
rate = models.DecimalField(max_digits=5,decimal_places=2)
Amount = models.DecimalField(max_digits=5,decimal_places=2)
I want to perform multiplication between Quantity and rate and store the result in Amount...
So I have done something like this:
from django.db.models import F
#receiver(pre_save, sender=Purchase)
def update_amount(sender,instance,*args,**kwargs):
totalamount = Purchase.objects.get(F('rate') * F('Quantity'))
instance.Amount = totalamount
But its giving me this error:
'CombinedExpression' object is not iterable
Do anyone have any idea how to do this???

But here you already have the instance, so the totalamount is simply:
#receiver(pre_save, sender=Purchase)
def update_amount(sender, instance, *args, **kwargs):
instance.Amount = instance.rate * instance.Quantity
That being said, if the Amount is always the rate multiplied with the Quantity, it is better to define a #property, since then you avoid data duplication, like:
class Purchase(models.Model):
Quantity = models.PositiveIntegerField()
rate = models.DecimalField(max_digits=5,decimal_places=2)
def amount(self):
return self.Quantity * self.rate

Related

Django form Data

Please I gotta a model I created with three fields input1,input2,total. So I generated a model form so that if I input the values of input 1 and input2 it will automatically multiply the the inputted values. Then on calling the save method it will save the inputted values and computed value to the database
Try this:
class Multiply(models.Model):
input1 = models.IntegerField()
input2 = models.IntegerField()
result = models.IntegerField(null=True, blank=True)
def __str__(self):
return str(self.input1) + " * " + str(self.input2) + " = " + str(self.result)
def save(self, *args, **kwargs):
self.result = self.input1 * self.input2
super().save(*args, **kwargs)

Django 'NoneType' object has no attribute 'amount'

I keep getting the same error 'NoneType' object has no attribute 'amount' over and over ever since I added an an amount field to my coupon code script.
This is my code;
class Coupon(models.Model):
code = models.CharField(max_length=15)
amount = models.FloatField()
def __str__(self):
return self.code
And here's the get_total code;
def get_total(self):
total = 0
amount = models.FloatField()
for order_item in self.items.all():
total += order_item.get_final_price()
total -= self.coupon.amount
return total
I have been trying to solve this with numerous solutions that didn't work. I would really appreciate it if anyone could tell me what I am doing wrong here
In your comment you say "get_final_price is a method of OrderItem". I'll assume when you say get_final_price you mean get_total.
Do all OrderItems have a coupon? If OrderItem.coupon can be null then you have to change get_total to something like:
def get_total(self):
total = 0
amount = models.FloatField()
for order_item in self.items.all():
total += order_item.get_final_price()
if self.coupon:
total -= self.coupon.amount
return total
in models.py all null and blank "true"
class Coupon(models.Model):
code = models.CharField(max_length=15,null=True, blank=True)
amount = models.FloatField(null=True, blank=True)
def __str__(self):
return self.code

I want to change the time calculation format (django models, virtual field)

model field code is this
created = models.DateTimeField(auto_now=True)
#property
def now_diff(self):
return timezone.now() - self.created
I have a question about django time circulation using virtual field
current output of time circulation is 5:26:34.349728
But I want to 5:26:34
Is there a way?
thanks for let me know ~!
i chaged to
#property
def now_diff(self):
s=timezone.now() - self.created
hours, remainder = divmod(s, 3600)
minutes, seconds = divmod(remainder, 60)
return '{:02}:{:02}:{:02}'.format(int(hours), int(minutes), int(seconds))
but error
TypeError: 'Todo' object is not subscriptable
TypeError: unsupported operand type(s) for divmod(): 'datetime.timedelta' and 'int'
Subtract the microseconds from timedelta which you've got
from datetime import timedelta
class MyModel(models.Model):
...
created = models.DateTimeField(auto_now=True)
#property
def now_diff(self):
delta = timezone.now() - self.created
return str(delta - timedelta(microseconds=delta.microseconds))
For more readable solution,
from datetime import timedelta
def chop_microseconds(delta):
return delta - timedelta(microseconds=delta.microseconds)
class MyModel(models.Model):
...
created = models.DateTimeField(auto_now=True)
#property
def now_diff(self):
return str(chop_microseconds(timezone.now() - self.created))
Some BG things
If we look into the Source code of __str__() function of timedelta class,
....
if self._microseconds:
s = s + ".%06d" % self._microseconds
...
which converts the string representation of the timedelta object.
So, here we substract the microsecond from timedelta and hence solved the problem :)
Maybe you can try like this(mostly copy pasted from this answer):
#property
def now_diff(self):
time_delta = timezone.now() - self.created
s = time_delta.seconds
hours, remainder = divmod(s, 3600)
minutes, seconds = divmod(remainder, 60)
return '{:02}:{:02}:{:02}'.format(int(hours), int(minutes), int(seconds))

How to call a custom method with arguments in the models.py from views.py

I have this example:
class MyModel(models.Model):
# Some fields...
price = models.FloatField()
def calculate(self, number):
return self.price * number
In the views:
def whatever(request, any_number):
m = MyModel.objects.all()
c = m.calculate(any_number)
# More code...
It's a really easy example because I want to do something similar, so how can I do this?
Thank you!
You need to do it in a for loop, since m is an array of objects:
for item in m:
result = item.calculate(any_number)
# do some stuff with the result

Django - Add online columns in "select"

I dont know if this is the best way to resolve my problem, if isn't , tell me plz :)
I have this model :
class userTrophy(models.Model):
user = models.ForeignKey(userInfo)
platinum = models.IntegerField()
gold = models.IntegerField()
silver = models.IntegerField()
bronze = models.IntegerField()
level = models.IntegerField()
perc_level = models.IntegerField()
date_update = models.DateField(default=datetime.now, blank=True)
Now i want to retrieve one user info, but i want add 3 new "columns" online :
total = platinum + gold + silver + bronze
point = platinum * 100 + gold * 50 + silver * 25 + bronze * 10
and sort by "point", after sort, put a new column, with a sequencial number: rank (1-n).
Can i do this ( or part of this ) working only with the model ?
I am sure there are many ways to achieve this behavior. The one I am thinking of right now is a Custom Model Manager and transient model fields.
Your class could look like so:
from django.db import models
from datetime import datetime
class UserTrophyManager(models.Manager):
def get_query_set(self):
query_set = super(UserTrophyManager, self).get_query_set()
for ut in query_set:
ut.total = ut.platinum + ut.gold + ut.silver + ut.bronze
ut.points = ut.platinum * 100 + ut.gold * 50 + ut.silver * 25 + ut.bronze * 10
return query_set
class UserTrophy(models.Model):
user = models.CharField(max_length=30)
platinum = models.IntegerField()
gold = models.IntegerField()
silver = models.IntegerField()
bronze = models.IntegerField()
level = models.IntegerField()
perc_level = models.IntegerField()
date_update = models.DateField(default=datetime.now, blank=True)
total = 0
point = 0
objects = UserTrophyManager()
class Meta:
ordering = ['points']
So you can use the following and get total and point calculated:
user_trophies = userTrophy.objects.all()
for user_trophy in user_trophies:
print user_trophy.total
Here's the way I would do it. Add the columns 'total' and 'points' to your model, like this:
class UserTrophy(models.Model):
...
total = models.IntegerField()
points = models.IntegerField()
...
Override the save method for your model:
def save(self, *args, **kwargs):
# Compute the total and points before saving
self.total = self.platinum + self.gold + self.silver + self.bronze
self.points = self.platinum * 100 + self.gold * 50 + \
self.silver * 25 + self.bronze * 10
# Now save the object by calling the super class
super(UserTrophy, self).save(*args, **kwargs)
With total and points as first class citizens on your model, your concept of "rank" becomes just a matter of ordering and slicing the UserTrophy objects.
top_ten = UserTrophy.objects.order_by('-points')[:10]
You'll also want to make sure you have your fields indexed, so your queries are efficient.
If you don't like the idea of putting these fields in your model, you might be able to use the extra feature of Django query set objects to compute your total and points on the fly. I don't use this very often, so maybe someone else can put together an example.
Also, I recommend for you to read PEP 8 for Python coding conventions.
This is more of a followup question than an answer, but is it possible to do something like:
class userTrophy(models.Model):
... stuff...
def points(self):
self.gold + self.silver + self.bronze
then call something like object.points in a template. Im just curious if that is a possibility