#16165: Annotations get crazy when .values has many arguments (MySQL)
----------------------------+----------------------------------------------
Reporter: dev@… | Owner: nobody
Type: Bug | Status: new
Milestone: | Component: Database layer (models, ORM)
Version: SVN | Severity: Normal
Keywords: aggregate, | Triage Stage: Unreviewed
annotate | Easy pickings: 0
Has patch: 0 |
----------------------------+----------------------------------------------
Models in "mars" project:
{{{
class BiddingRule(models.Model):
name = models.CharField(max_length=80)
...
class TagList(models.Model):
name = models.CharField(max_length=50)
...
def __unicode__(self):
return self.name
class Property(models.Model):
property = models.CharField(max_length=100)
def __unicode__(self):
return self.property
class Meta:
ordering = ['property']
verbose_name_plural = 'properties'
class Account(models.Model):
"""A property has 1..n accounts"""
username = models.CharField(max_length=200)
password = models.CharField(max_length=200)
ENGINE_CHOICES = (
(1, 'Google'),
(2, 'Yahoo'),
(3, 'Bing'),
)
property = models.ForeignKey(Property)
engine = models.IntegerField(choices=ENGINE_CHOICES)
class Campaign(models.Model):
"""An account has 1..n campaigns"""
campaign = models.CharField(max_length=500)
engine_id = models.BigIntegerField()
account = models.ForeignKey(Account)
STATUS_CHOICES = (
(1, 'Active'),
(2, 'Paused'),
(3, 'Deleted'),
)
status = models.IntegerField(choices=STATUS_CHOICES, default=1)
budget = models.FloatField(default=0.0)
tags = models.ManyToManyField('TagList')
visible_tags = models.CharField(max_length=200, blank=True, null=True)
bidding_rule = models.ForeignKey(BiddingRule, null=True, blank=True)
class Meta:
ordering = ['campaign']
def __unicode__(self):
return self.campaign
class AdGroup(models.Model):
"""A Campaign has 1..n AdGroups"""
ad_group = models.CharField(max_length=500)
engine_id = models.BigIntegerField()
campaign = models.ForeignKey(Campaign)
STATUS_CHOICES = (
(1, 'Active'),
(2, 'Paused'),
(3, 'Deleted'),
(4, 'Draft'),
)
status = models.IntegerField(choices=STATUS_CHOICES, default=1)
max_cpc = models.DecimalField(max_digits=7, decimal_places=4,
default=Decimal('0'))
content_max_cpc = models.DecimalField(max_digits=7, decimal_places=4,
default=Decimal('0'))
tags = models.ManyToManyField('TagList')
visible_tags = models.CharField(max_length=200, blank=True, null=True)
bidding_rule = models.ForeignKey(BiddingRule, null=True, blank=True)
class Meta:
ordering = ['ad_group']
class CampaignStat(models.Model):
"""Stats by campaign"""
date = models.DateField()
account = models.ForeignKey(Account)
campaign = models.ForeignKey(Campaign)
impressions = models.IntegerField(default=0)
clicks = models.IntegerField(default=0)
cost = models.DecimalField(max_digits=13, decimal_places=4,
default=Decimal('0'))
conversions = models.IntegerField(default=0)
revenue = models.DecimalField(max_digits=13, decimal_places=4,
default=Decimal('0'))
average_position = models.FloatField(default=0.0)
class AdGroupStat(models.Model):
"""Stats by ad group"""
date = models.DateField()
account = models.ForeignKey(Account)
ad_group = models.ForeignKey(AdGroup)
impressions = models.IntegerField(default=0)
clicks = models.IntegerField(default=0)
cost = models.DecimalField(max_digits=13, decimal_places=4,
default=Decimal('0'))
conversions = models.IntegerField(default=0)
revenue = models.DecimalField(max_digits=13, decimal_places=4,
default=Decimal('0'))
average_position = models.FloatField(default=0.0)
}}}
And here is the crazy annotation issue I am running into. Note the GROUP
BY section of each query.
{{{
>>> from mars.models import *
>>> from django.db.models import Sum
>>> annotations = {
'_impressions': Sum('impressions'),
'_clicks': Sum('clicks'),
'_cost': Sum('cost'),
'_average_position': Avg('average_position'),
'_conversions': Sum('conversions'),
'_revenue': Sum('revenue')
}
>>> ad_group_values = ['ad_group__id',
'ad_group__engine_id',
'ad_group__ad_group',
'ad_group__campaign__account__engine',
'ad_group__campaign__campaign',
'ad_group__max_cpc',
'ad_group__content_max_cpc',
'ad_group__status',
'ad_group__bidding_rule__name',
'ad_group__visible_tags']
>>> stats = AdGroupStat.objects.values(*ad_group_values)
>>> stats = stats.annotate(**annotations)
>>> print(stats.query)
SELECT `mars_adgroupstat`.`ad_group_id`, `mars_adgroup`.`engine_id`,
`mars_adgroup`.`ad_group`, `mars_account`.`engine`,
`mars_campaign`.`campaign`, `mars_adgroup`.`max_cpc`,
`mars_adgroup`.`content_max_cpc`, `mars_adgroup`.`status`,
`mars_biddingrule`.`name`, `mars_adgroup`.`visible_tags`,
AVG(`mars_adgroupstat`.`average_position`) AS `_average_position`,
SUM(`mars_adgroupstat`.`conversions`) AS `_conversions`,
SUM(`mars_adgroupstat`.`clicks`) AS `_clicks`,
SUM(`mars_adgroupstat`.`cost`) AS `_cost`,
SUM(`mars_adgroupstat`.`revenue`) AS `_revenue`,
SUM(`mars_adgroupstat`.`impressions`) AS `_impressions` FROM
`mars_adgroupstat` INNER JOIN `mars_adgroup` ON
(`mars_adgroupstat`.`ad_group_id` = `mars_adgroup`.`id`) INNER JOIN
`mars_campaign` ON (`mars_adgroup`.`campaign_id` = `mars_campaign`.`id`)
INNER JOIN `mars_account` ON (`mars_campaign`.`account_id` =
`mars_account`.`id`) LEFT OUTER JOIN `mars_biddingrule` ON
(`mars_adgroup`.`bidding_rule_id` = `mars_biddingrule`.`id`)
GROUP BY `mars_adgroupstat`.`id`, `mars_adgroupstat`.`ad_group_id`,
`mars_adgroup`.`engine_id`, `mars_adgroup`.`ad_group`,
`mars_account`.`engine`, `mars_campaign`.`campaign`,
`mars_adgroup`.`max_cpc`, `mars_adgroup`.`content_max_cpc`,
`mars_adgroup`.`status`, `mars_biddingrule`.`name`,
`mars_adgroup`.`visible_tags` ORDER BY NULL
>>> stats = AdGroupStat.objects.values(*ad_group_values[:-1])
>>> stats = stats.annotate(**annotations)
>>> print(stats.query)
SELECT `mars_adgroupstat`.`ad_group_id`, `mars_adgroup`.`engine_id`,
`mars_adgroup`.`ad_group`, `mars_account`.`engine`,
`mars_campaign`.`campaign`, `mars_adgroup`.`max_cpc`,
`mars_adgroup`.`content_max_cpc`, `mars_adgroup`.`status`,
`mars_biddingrule`.`name`, AVG(`mars_adgroupstat`.`average_position`) AS
`_average_position`, SUM(`mars_adgroupstat`.`conversions`) AS
`_conversions`, SUM(`mars_adgroupstat`.`clicks`) AS `_clicks`,
SUM(`mars_adgroupstat`.`cost`) AS `_cost`,
SUM(`mars_adgroupstat`.`revenue`) AS `_revenue`,
SUM(`mars_adgroupstat`.`impressions`) AS `_impressions` FROM
`mars_adgroupstat` INNER JOIN `mars_adgroup` ON
(`mars_adgroupstat`.`ad_group_id` = `mars_adgroup`.`id`) INNER JOIN
`mars_campaign` ON (`mars_adgroup`.`campaign_id` = `mars_campaign`.`id`)
INNER JOIN `mars_account` ON (`mars_campaign`.`account_id` =
`mars_account`.`id`) LEFT OUTER JOIN `mars_biddingrule` ON
(`mars_adgroup`.`bidding_rule_id` = `mars_biddingrule`.`id`)
GROUP BY `mars_adgroupstat`.`ad_group_id`, `mars_adgroup`.`engine_id`,
`mars_adgroup`.`ad_group`, `mars_account`.`engine`,
`mars_campaign`.`campaign`, `mars_adgroup`.`max_cpc`,
`mars_adgroup`.`content_max_cpc`, `mars_adgroup`.`status`,
`mars_biddingrule`.`name`, `mars_adgroupstat`.`ad_group_id`,
`mars_adgroup`.`engine_id`, `mars_adgroup`.`ad_group`,
`mars_account`.`engine`, `mars_campaign`.`campaign`,
`mars_adgroup`.`max_cpc`, `mars_adgroup`.`content_max_cpc`,
`mars_adgroup`.`status`, `mars_biddingrule`.`name` ORDER BY NULL
>>> stats = AdGroupStat.objects.values(*ad_group_values[1:])
>>> stats = stats.annotate(**annotations)
>>> print(stats.query)
SELECT `mars_adgroup`.`engine_id`, `mars_adgroup`.`ad_group`,
`mars_account`.`engine`, `mars_campaign`.`campaign`,
`mars_adgroup`.`max_cpc`, `mars_adgroup`.`content_max_cpc`,
`mars_adgroup`.`status`, `mars_biddingrule`.`name`,
`mars_adgroup`.`visible_tags`, AVG(`mars_adgroupstat`.`average_position`)
AS `_average_position`, SUM(`mars_adgroupstat`.`conversions`) AS
`_conversions`, SUM(`mars_adgroupstat`.`clicks`) AS `_clicks`,
SUM(`mars_adgroupstat`.`cost`) AS `_cost`,
SUM(`mars_adgroupstat`.`revenue`) AS `_revenue`,
SUM(`mars_adgroupstat`.`impressions`) AS `_impressions` FROM
`mars_adgroupstat` INNER JOIN `mars_adgroup` ON
(`mars_adgroupstat`.`ad_group_id` = `mars_adgroup`.`id`) INNER JOIN
`mars_campaign` ON (`mars_adgroup`.`campaign_id` = `mars_campaign`.`id`)
INNER JOIN `mars_account` ON (`mars_campaign`.`account_id` =
`mars_account`.`id`) LEFT OUTER JOIN `mars_biddingrule` ON
(`mars_adgroup`.`bidding_rule_id` = `mars_biddingrule`.`id`)
GROUP BY `mars_adgroup`.`engine_id`, `mars_adgroup`.`ad_group`,
`mars_account`.`engine`, `mars_campaign`.`campaign`,
`mars_adgroup`.`max_cpc`, `mars_adgroup`.`content_max_cpc`,
`mars_adgroup`.`status`, `mars_biddingrule`.`name`,
`mars_adgroup`.`visible_tags`, `mars_adgroup`.`engine_id`,
`mars_adgroup`.`ad_group`, `mars_account`.`engine`,
`mars_campaign`.`campaign`, `mars_adgroup`.`max_cpc`,
`mars_adgroup`.`content_max_cpc`, `mars_adgroup`.`status`,
`mars_biddingrule`.`name`, `mars_adgroup`.`visible_tags` ORDER BY NULL
>>>
}}}
In the first query, using all 10 arguments in .values, the GROUP BY has 11
items as it seems to be adding the local model id:
{{{
GROUP BY `mars_adgroupstat`.`id`, `mars_adgroupstat`.`ad_group_id`,
`mars_adgroup`.`engine_id`, `mars_adgroup`.`ad_group`,
`mars_account`.`engine`, `mars_campaign`.`campaign`,
`mars_adgroup`.`max_cpc`, `mars_adgroup`.`content_max_cpc`,
`mars_adgroup`.`status`, `mars_biddingrule`.`name`,
`mars_adgroup`.`visible_tags`
}}}
In the second or third queries, using 9 arguments in .values, the GROUP BY
has 18 items as it seems to be doubling the GROUP BY args:
{{{
GROUP BY `mars_adgroup`.`engine_id`, `mars_adgroup`.`ad_group`,
`mars_account`.`engine`, `mars_campaign`.`campaign`,
`mars_adgroup`.`max_cpc`, `mars_adgroup`.`content_max_cpc`,
`mars_adgroup`.`status`, `mars_biddingrule`.`name`,
`mars_adgroup`.`visible_tags`, `mars_adgroup`.`engine_id`,
`mars_adgroup`.`ad_group`, `mars_account`.`engine`,
`mars_campaign`.`campaign`, `mars_adgroup`.`max_cpc`,
`mars_adgroup`.`content_max_cpc`, `mars_adgroup`.`status`,
`mars_biddingrule`.`name`, `mars_adgroup`.`visible_tags`
GROUP BY `mars_adgroupstat`.`ad_group_id`, `mars_adgroup`.`engine_id`,
`mars_adgroup`.`ad_group`, `mars_account`.`engine`,
`mars_campaign`.`campaign`, `mars_adgroup`.`max_cpc`,
`mars_adgroup`.`content_max_cpc`, `mars_adgroup`.`status`,
`mars_biddingrule`.`name`, `mars_adgroupstat`.`ad_group_id`,
`mars_adgroup`.`engine_id`, `mars_adgroup`.`ad_group`,
`mars_account`.`engine`, `mars_campaign`.`campaign`,
`mars_adgroup`.`max_cpc`, `mars_adgroup`.`content_max_cpc`,
`mars_adgroup`.`status`, `mars_biddingrule`.`name`
}}}
The first query does not return what I want, while the second and third
return correctly, but look pretty funky. Using MySQL 5.1.41-3ubuntu12.8,
Django SVN 16332, Python 2.6.5 on Ubuntu 10.04.
--
Ticket URL: <https://code.djangoproject.com/ticket/16165>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/django-updates?hl=en.