Amon
Amon

Reputation: 2951

Calculate a number in a Django model from another model's data

I want to take data (amount_spent) from the field of each user and add those numbers up and display them in another field (total_revenue) from a different model (RevenueInfo).

from __future__ import unicode_literals
from django.contrib.auth.models import User
from django.db import models
from django import forms, views

# Create your models here.
#LoginInfo is being used, LoginForms in forms.py is
class LoginInfo(models.Model):
    username = models.CharField('', max_length=10)
    password = models.CharField('', max_length=15)

class ExtendedProfile(models.Model):
    user = models.OneToOneField(User)
    amount_spent = models.DecimalField(max_digits=6, decimal_places=2)

class RevenueInfo(models.Model):
    total_amount_spent = models.DecimalField(max_digits=6, decimal_places=2, default=0)
    total_revenue = models.ForeignKey(ExtendedProfile, null=True)

class Product(models.Model):
     category = models.CharField(max_length=100)
     name = models.CharField(max_length=100)
     description = models.TextField()
     #photo = models.ImageField()
     price_CAD = models.DecimalField(max_digits=6, decimal_places=2)
     quantity = models.DecimalField(max_digits=2, decimal_places=0, null=True)

How could I go about this? Would I iterate of each Usermodel and find User.amount_spent then add that to RevenueInfo.total_revenue? I'm not sure how to put that into code. Also I'm pretty sure I don't need both total_amount_spent and total_revenue but I feel like I need a ForeignKey

Upvotes: 0

Views: 2385

Answers (3)

birophilo
birophilo

Reputation: 962

You could add a classmethod to the ExtendedProfile model to aggregate the amount_spent value for each User (which bypasses the need for a separate RevenueInfo model):

from django.db.models import Sum

class ExtendedProfile(models.Model):
....
    @classmethod
    def total_user_spend(cls):
        return cls.objects.aggregate(total=Sum('amount_spent'))

Then you can get the total spend using ExtendedProfile.total_user_spend():

>>> ExtendedProfile.total_user_spend()
{'total': Decimal('1234.00')}

Upvotes: 1

Igonato
Igonato

Reputation: 10777

Avoid iterating over database entities in python (it can get really slow). Look into aggregation, it allows you to efficiently get sum (average, max, min, etc...) of values in a database:

>>> from django.db.models import Sum
>>> ExtendedProfile.objects.all().aggregate(Sum('amount_spent'))
{'amount_spent__sum': Decimal('1234.56')}
>>> # ... do whatever you want with the return value

Upvotes: 1

PyManiac
PyManiac

Reputation: 504

Yes, you can write a method for that in your model. There are 2 ways for it. 1) Writing a method that calculates the values and sets it to a instance value. 2) Writing a method that calculates the value and directly returns it.

For example purpose, here is the code for 2nd type.

# models.py
def total_amount_spent(self):
    temp_values = [int(user.amount_spent) for user in ExtendedProfile.objects.all()]
    return sum(temp_values)

And for using that value in views , but remeber it would be an integer by default

#views.py
value = RevenueInfo.total_amount_spent()

Upvotes: 1

Related Questions