【问题标题】:Calculate a number in a Django model from another model's data从另一个模型的数据计算 Django 模型中的数字
【发布时间】:2017-05-15 02:43:47
【问题描述】:

我想从每个用户的字段中获取数据 (amount_spent),然后将这些数字相加并显示在来自不同模型 (RevenueInfo) 的另一个字段 (total_revenue) 中。

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)

我该怎么办?我会遍历每个Usermodel 并找到User.amount_spent 然后将其添加到RevenueInfo.total_revenue 吗?我不确定如何将其放入代码中。另外我很确定我不需要total_amount_spenttotal_revenue,但我觉得我需要ForeignKey

【问题讨论】:

    标签: python django


    【解决方案1】:

    您可以将classmethod 添加到ExtendedProfile 模型以聚合每个用户的amount_spent 值(这绕过了单独的RevenueInfo 模型的需要):

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

    然后您可以使用ExtendedProfile.total_user_spend() 获得总支出:

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

    【讨论】:

    • 抱歉回复晚了,谢谢。但是,这会是在管理页面/实际字段中显示它的最佳方式吗?基本上我需要像models.DecimalField('amount_spent) 这样的东西。显然这不起作用,但你知道我的意思
    • 需要澄清才能完全关注您。如果这是为了参考和与单个用户字段进行比较,那么您可以通过在 django 管理员 docs.djangoproject.com/en/1.11/ref/contrib/admin 中使用 fieldsets 添加描述来在 ExtendedProfile 表单上显示总支出,例如:
    • class ExtendedProfileAdmin(admin.ModelAdmin): fieldsets = [ (None, { 'fields': ('user', ) }), ("总用户花费为 {}".format(ExtendedProfile. total_user_spend()['total']), { 'fields':('amount_spent', ), }), ] admin.site.register(ExtendedProfile, ExtendedProfileAdmin)
    • 一旦它被声明为classmethod,您可以在任何视图中使用ExtendedProfile.total_user_spend(),无论是在模板中还是在管理页面上,并且可能不需要在数据库中保存该值,除非你有一个特殊的原因。但是,如果您愿意这样做,那么每次更新 ExtendedProfile 时将值设置为 total_user_spend。您可以使用 Signals 或覆盖 save 方法来做到这一点。 stackoverflow.com/questions/35949755/…。另见docs.djangoproject.com/en/1.11/topics/signals
    • 来自 Python 文档:docs.python.org/2/library/functions.html#classmethod“类方法接收类作为隐式第一个参数,就像实例方法接收实例一样。”使用它来作用于类本身而不是它的任何特定实例——在这种情况下,我们想要所有用户而不是单个用户。而默认情况下,类方法的第一个参数是对当前类实例的引用,按照约定称为“self”,而这里称为“cls”。比较@classmethod@property@staticmethod
    【解决方案2】:

    是的,您可以在模型中为此编写一个方法。有两种方法。 1) 编写一个计算值并将其设置为实例值的方法。 2) 编写一个计算值并直接返回的方法。

    例如,这里是第二种类型的代码。

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

    在 views 中使用该值,但请记住,默认情况下它是一个整数

    #views.py
    value = RevenueInfo.total_amount_spent()
    

    【讨论】:

      【解决方案3】:

      避免在 python 中迭代数据库实体(它会变得非常慢)。查看aggregation,它可以让您有效地获取数据库中值的总和(平均值、最大值、最小值等...):

      >>> 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-08-08
        • 2022-01-15
        • 1970-01-01
        • 2021-09-21
        • 2021-12-31
        • 1970-01-01
        • 2015-04-12
        相关资源
        最近更新 更多