2017-07-19 107 views
0

我需要顯示報價的平均值。問題是我必須計算多對多字段組合的平均值。我也必須將所有這些分頁。計算平均值時表現不佳

我已經做到了。問題是它的性能很差,我正在尋找解決方法。

這個模型看起來是這樣的:

class Offer(models.Model): 
    price = DecimalField(max_digits=10, decimal_places=2) 
    quantity = PositiveIntegerField() 
    product = ForeignKey(Product) 
    qualifiers = ManyToManyField(Qualifier) 

相關的代碼來計算平均值是這樣的:

def get_average(product, qualifiers, users=None): 
    offers = Offer.objects.filter(product=product) 

    if users is not None: 
     offers = offers.filter(user__in=users) 

    for qualifier in qualifiers: 
     offers = offers.filter(qualifiers=qualifier) 

    if not offers.count(): 
     return None 

    offers = offers.aggregate(
     quantity_x_price_sum=Sum(F('quantity') * F('price'), output_field=FloatField()), 
     quantity_total=Sum('quantity') 
    ) 

    # Weighted average 
    return offers['quantity_x_price_sum']/offers['quantity_total'] 


def get_averages(product, limit=20, users=None): 
    averages = [] 

    colors = product.qualifiers.filter(type=1) 
    sizes = product.qualifiers.filter(type=2) 
    other = product.qualifiers.filter(type=3) 

    qualifiers = [colors, sizes, other] 
    combinations = itertools.product(*qualifiers) 

    for combination in combinations: 
     average = get_average(product, combination, users) 
     if average is not None: 
      averages.append(average) 

      if len(averages) == limit: 
       return averages 

    return averages 

的主要問題是在itertools.product(*預選賽)。這可以產生數百個組合。 直到len(價格)==限制,它必須迭代它們中的每一個並執行查詢。

任何幫助將受到歡迎。謝謝。

+0

第一眼看去,你正在創建一個list組合列表(itertools.product(* qualifiers))'來獲得你的組合,然後你將它傳遞給for循環。對此的改進是創建一個生成器'組合= itertools.product(*限定符)',然後您可以將組合傳遞到for循環。這將減少生成列表的開銷,然後迭代它。 –

回答

1

爲什麼不直接用查詢本身進行平均聚合?

從Django文檔:

# Average price across all books. 
>>> from django.db.models import Avg 
>>> Book.objects.all().aggregate(Avg('price')) 
{'price__avg': 34.35} 

https://docs.djangoproject.com/en/1.11/topics/db/aggregation/

編輯:還有更復雜的方式來查詢此,希望這可以幫助。不確定它如何處理非數字數據。

+0

要添加到此答案,您應該 - 作爲第一步 - 嘗試儘可能多地使用ORM。只有當你不能在ORM中完成時,才能將所有東西拉到Python中。這並不總是適用,但它適用於大部分/中間問題。 –

+0

我需要加權平均值,這與平均值不同(https://en.wikipedia.org/wiki/Weighted_arithmetic_mean)。這就是爲什麼我把這個總和,做計算。 而我不能直接計算所有優惠,我必須爲每個產品的限定符(然後分頁)的每個組合。我認爲這是主要問題。 謝謝。 – nickname123