python - Avoiding cartesian product with Django -
i have following 3 tables defined.
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"
for operator, retrieve alertscore
, transactioncount
given date range. query i'm using looks this:
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")
this query performs cartesian product , returns rows in operatoralerts , operatorsummary table match query. returns:
{'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}
i'd fix following result:
{'alertsummary__alertscore': 607, 'displayname': u'jimmy', 'transactionsummary__transactioncount': 266}
all results collapsed 1 row alertscore , transactioncount summed.
is possible? can fall making separate query operatoralerts , operatorsummary , iterating on result set in python results want or calling .aggregate
, i'm sure there must better way?
try reversing order in apply values()
, annotate()
methods. values()
should come first:
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"))
this group results fields mentioned in values()
, generate annotation each group. order significant - as documented.
applying values()
, annotate()
in way (i.e. annotate()
before values()
) generate annotations every item separately.
please note code above group results displayname
. may want group different field, example pk
.
also, assume in real code want values multiple operators @ once. if queried 1 operator @ time (like in example) better of using aggregate()
instead of annotate()
.
Comments
Post a Comment