2017-07-19 26 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(prices)== limitになるまでは、それぞれを反復してクエリを実行する必要があります。

助けを歓迎します。ありがとう。

+0

最初に、あなたの組み合わせを取得してforループに渡すために 'combinations = list(itertools.product(* qualifiers))'リストを作成しています。これに対する改良は、ジェネレータ 'combined = itertools.product(* qualifiers)'を生成することです。そして、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/

EDIT:これを照会するために、より複雑な方法がありますが、うまくいけば、このことができます。非数値データの処理方法がわからない。

+0

この回答に追加するには、最初のステップとして、可能な限りORMを多用してください。 ORMで実行できない場合にのみ、すべてをPythonにプルします。これは必ずしも当てはまるとは限りませんが、最も大きな/中間の問題には当てはまります。 –

+0

平均(https://en.wikipedia.org/wiki/Weighted_arithmetic_mean)とは異なる加重平均が必要です。それで、計算を行うために、私はそれを集計しました。 私はすべてのオファーを直接計算することはできません。各商品の修飾子の組み合わせごとに(そしてページ付けする)必要があります。私はこれが主要な問題だと思う。 ありがとうございます。 – nickname123