【问题标题】:optimizing this django code?优化这个django代码?
【发布时间】:2010-12-14 01:19:24
【问题描述】:

我遇到了一些性能问题,因为我进行了很多不知道如何减少的查询调用。

user_item_rel_set 是用户和项目之间的 m2m 关系,显示用户为特定项目支付了多少费用。每个项目可以有多个用户和买家,我正在尝试获取特定用户的 m2m 关系。

        # find anything that you bought or used and how much you paid for it
        u = User.objects.get(id=self.uid)
        t = self.list.filter(user_item_rel__user__exact=u)
        y = self.list.filter(buyer_item_rel__buyer__exact=u)

        items = t | y 
        items = items.distinct()
        u = User.objects.get(id=self.uid)
        for t in items:
            try: 
                t.price = t.user_item_rel_set.get(user=u).payment_amount
            except:
                t.price = -1 * t.buyer_item_rel_set.get(buyer=u).payment_amount
        return items

在另一个例子中

    for i in new_list:
        if str(i.tag) not in x:
            x[str(i.tag)] = 0 

        if houseMode == 0:
            x[str(i.tag)] += float(i.user_item_rel_set.get(user__id__exact=self.uid).payment_amount)
        else:
            x[str(i.tag)] += float(i.price)

【问题讨论】:

    标签: python django


    【解决方案1】:

    您的模型中的一些额外代码会有所帮助,因为很难看到“项目”查询集包含什么。

    无论如何我都会尽力帮忙的......

    因为您已经对用户和项目之间的关系进行了建模,所以当您可以简单地选择您感兴趣的子集时,无需遍历该查询集中的每个项目。

    再一次,我在遵循您的应用程序逻辑时遇到了一些困难,但我认为您的查询可以简化为这种性质:

    # Find all the items where this user is the "user"
    user_items = items.filter(user_item_rel_set__user=u)
    
    # Find all the items where this user is the "buyer"
    buyer_items = items.filter(user_item_rel_set__buyer=u)
    

    我不太明白您为什么在循环中将这些值分配给“t.price”,否则我会扩展该代码。

    如果这对你的表现没有帮助,我推荐dumping your SQL queries to the console,这样你就可以准确地看到 ORM 背后发生了什么。在这样的逻辑中,只需要几条 SQL 语句就可以得出您的计算。

    此外,在接近货币价值的任何地方使用浮点数据类型 (float) 通常是个坏主意。浮点数据类型通常用于性能比精度更重要的科学应用程序。如果您在处理金钱问题,精度几乎总是比性能更重要,因此您可以使用能够精确表示的数据类型,例如 decimal.Decimal everywhere

    编辑

    鉴于 cmets,我建议使用“relationship”对象而不是 Item 来开始您的查询。由于您的示例没有告诉我该类的名称,因此我假设它称为 UserItem:

    from django.db.models import Q
    from decimal import Decimal
    
    price = Decimal('0')
    
    # Get all UserItems where this user is the user or buyer
    interesting_items = UserItem.objects.filter((Q(user=u) | Q(buyer=u)))
    for ii in interesting_items:
        if ii.user == u:
            price += ii.payment_amount
        elif ii.buyer == u:
            price -= ii.payment_amount
        else:
            assert False, "Oops, this shouldn't happen"
    
    # Do something with 'price'...
    

    Django“Q”工具让您的查询更加精细。如果您需要根据项目的某些属性进行过滤,请将其也放入其中。

    在您的示例中仍然让我感到困惑的部分是,当很明显许多用户将共享该项目时,为什么要将“价格”分配给项目对象。

    编辑 2

    如果您感兴趣的话,您也可以使用aggregation API 让 DBMS 计算总和:

    from django.db.models import Sum
    buyer_price = UserItem.objects.filter(item=i, user=u).aggregate(
                     Sum('payment_amount'))['payment_amount__sum']
    

    【讨论】:

    • 所以商品有价格,它的 m2m 关系 (user_item_rel) 包含用户为该商品支付的费用。我有一个用户参与的项目列表(正是您拥有的代码),并且我正在尝试检索用户为每个项目支付的费用,尽管如果不为每个项目敲击数据库,我就无法做到这一点.
    • 所以'payment_amount'字段存储在用户和项目之间的关系对象上?我假设 m2m 关系有它自己的模型?
    • 即使我的后一个例子仍然缺少一些东西,但我不能从你给出的细节中说出什么。也许您只需要一张从那里开始定价的物品地图,这非常简单。如果你描述了你有什么输入和你期望什么输出,也许会更容易提供帮助?
    • 当然。假设我有一个物品清单:奶酪 4 美元,面包 5 美元,牛奶 4 美元。我支付$3、$3、$2$,其余由B人支付。奶酪的Item模型是:name-cheese,价格4。我的m2m是item=cheese,user=me,payment=$2 .对于所有项目,B 人相同。现在我得到了这些项目的清单,我想知道我为每个项目支付了多少。因此,鉴于上面的代码,我查看每个项目(假设 i)并执行 i.user_item_rel_set.get(user=me)。这给了我2美元。然后我做剩下的。这是否澄清了事情?
    猜你喜欢
    • 2011-11-10
    • 1970-01-01
    • 2017-07-13
    • 1970-01-01
    • 2012-03-13
    • 1970-01-01
    • 1970-01-01
    • 2014-12-28
    • 1970-01-01
    相关资源
    最近更新 更多