2013-10-07 62 views
0

我有以下三個定義的表。避免與Django的笛卡爾積

class Operator(models.Model): 
    DisplayName = models.CharField(max_length=64) 

    class Meta: 
     app_label = "Experiment" 
     db_table = "EXPERIMENT_OPERATOR" 

class OperatorSummary(models.Model): 
    Operator = models.ForeignKey(Operator, related_name="TransactionSummary") 
    TransactionCount = models.IntegerField() 
    TransactionValue = models.DecimalField(max_digits=18, decimal_places=2) 
    StartTime = models.DateTimeField(default=timezone.now()) 

    class Meta: 
     app_label = "Experiment" 
     db_table = "EXPERIMENT_OPERATORSUMMARY" 

class OperatorAlerts(models.Model): 
    Operator = models.ForeignKey(Operator, related_name="AlertSummary") 
    AlertScore = models.IntegerField() 
    AlertCount = models.IntegerField() 
    StartTime = models.DateTimeField(default=timezone.now()) 

    class Meta: 
     app_label = "Experiment" 
     db_table = "EXPERIMENT_OPERATORALERTS" 

操作員,我想找回AlertScoreTransactionCount給定日期範圍。查詢我使用看起來像這樣:

tz = timezone.get_default_timezone()  
vs = Operator.objects.filter(DisplayName="Jimmy", 
          TransactionSummary__StartTime__gte=tz.localize(datetime(year=2013, month=10, day=1)), 
          AlertSummary__StartTime__gte=tz.localize(datetime(year=2013, month=10, day=1)))\ 
    .annotate(TotalTransactions=Sum("TransactionSummary__TransactionCount"), 
       TotalAlerts=Sum("AlertSummary__AlertScore"))\ 
    .values("DisplayName", "TransactionSummary__TransactionCount", "AlertSummary__AlertScore") 

此查詢執行笛卡爾乘積,並返回與查詢匹配的OperatorAlerts和OperatorSummary表中的所有行。這是它返回:

{'AlertSummary__AlertScore': 20, 'DisplayName': u'Jimmy', 'TransactionSummary__TransactionCount': 10} 
{'AlertSummary__AlertScore': 44, 'DisplayName': u'Jimmy', 'TransactionSummary__TransactionCount': 10} 
{'AlertSummary__AlertScore': 543, 'DisplayName': u'Jimmy', 'TransactionSummary__TransactionCount': 10} 
{'AlertSummary__AlertScore': 20, 'DisplayName': u'Jimmy', 'TransactionSummary__TransactionCount': 22} 
{'AlertSummary__AlertScore': 44, 'DisplayName': u'Jimmy', 'TransactionSummary__TransactionCount': 22} 
{'AlertSummary__AlertScore': 543, 'DisplayName': u'Jimmy', 'TransactionSummary__TransactionCount': 22} 
{'AlertSummary__AlertScore': 20, 'DisplayName': u'Jimmy', 'TransactionSummary__TransactionCount': 234} 
{'AlertSummary__AlertScore': 44, 'DisplayName': u'Jimmy', 'TransactionSummary__TransactionCount': 234} 
{'AlertSummary__AlertScore': 543, 'DisplayName': u'Jimmy', 'TransactionSummary__TransactionCount': 234} 

我想解決這個問題,使我得到以下結果:

{'AlertSummary__AlertScore': 607, 'DisplayName': u'Jimmy', 'TransactionSummary__TransactionCount': 266} 

所有的結果是摺疊成一排,其中AlertScore和TransactionCount相加。

這可能嗎?我總是會回頭爲OperatorAlerts和OperatorSummary分別查詢,然後遍歷Python中的結果集以獲得我想要的結果或調用.aggregate,但是我確定必須有更好的方法?

回答

1

嘗試顛倒您應用values()annotate()方法的順序。 values()應該先:

vs = Operator.objects.filter(DisplayName="Jimmy", 
          TransactionSummary__StartTime__gte=tz.localize(datetime(year=2013, month=10, day=1)), 
          AlertSummary__StartTime__gte=tz.localize(datetime(year=2013, month=10, day=1)))\ 
    .values("DisplayName")\ 
    .annotate(TotalTransactions=Sum("TransactionSummary__TransactionCount"), 
       TotalAlerts=Sum("AlertSummary__AlertScore")) 

這將組的結果通過在values()提到字段,然後生成用於每個組的註釋。訂單非常重要 - as documented

以您的方式應用values()annotate()(即annotate()values()之前)將分別爲每個項目生成註釋。

請注意,上面的代碼將DisplayName的結果進行分組。您可能希望按不同的字段進行分組,例如pk

另外,我假設在你真實的代碼中,你會想要一次獲得多個操作符的值。如果你總是一次詢問一個運營商(就像你在你的例子中那樣),你最好使用aggregate()而不是annotate()

+0

非常感謝您的幫助。你是正確的,我想一次查詢多個操作員。然而,我'annotate'仍然是我需要的,因爲我希望'TotalTransactions'和'TotalAlerts'適用於每個用戶,而不是所有用戶的聚合。 – CadentOrange

+0

我同意,這正是我的意思。我認爲這句話有點混亂,因爲我使用了錯誤的語法形式。我現在糾正了它。 –