开发者

optimizing this django code?

I'm having some performance issues because I'm making a lot of query calls that I'm not sure how to reduce.

user_item_rel_set is a m2m relation between user and items showing how much a user paid for a particular item. Each item can have multiple users and buyers, and I'm trying to get the m2m relation for a particular user.

        # 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

and at another instance

    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)


Some additional code from your model would help, because it's hard to see what the 'items' queryset contains.

I will try to help anyway...

Because you've modeled a relationship between users and items, there is no need to iterate over every item in that queryset when you can simply select the subset that are interesting to you.

Again, I'm having a bit of difficulty following your application logic, but I think your queries can be reduced to something of this nature:

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

I don't quite follow why you are assigning these values to 't.price' in the loop or I would expand on that code.

If that doesn't help your performance, I recommend dumping your SQL queries to the console so you can see exactly what's going on behind the ORM. In logic like this, it shouldn't take more than a handful of SQL statements to arrive at your calculation.

Furthermore, it is generally a bad idea to use floating point datatypes (float) anywhere in proximity to a monetary value. Floating point datatypes are generally for scientific applications where performance is more important than precision. If you're dealing with money, precision is almost always more important than performance, so you use a datatype capable of exact representation like decimal.Decimal everywhere.

Edit

Given the comments, I recommend starting your query with the "relationship" object instead of the Item. Since your sample doesn't tell me the name of that class, I will assume it's called 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'...

The Django "Q" facility lets you get a little more granular with your queries. If you need to filter based on some attribute of the item, throw that in there too.

The part that still confuses me in your examples, is why are you assigning 'price' to the item object when it is clear that many users will share that item.

Edit 2

You can also use the aggregation API to let the DBMS compute the sum if that's all you're interested in:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜