Django ORM:如何在没有rawsql的情况下使用Count()(子查询)过滤注释

时间:2017-01-31 12:30:24

标签: mysql django

对于列表查询,我想显示特定网站上特定产品的价格。

我已经找到了一种使用RawSQL的方法,这是我以前从未做过的事情。我忽略了什么吗?

    queryset = Price.objects.all()
    site_annotations = {}
    for site in Site.objects.all():
        site_annotations['num_prices_{}'.format(site.name)] = RawSQL(
            'SELECT COUNT(id) '
            'FROM `product_siteprice` '
            'WHERE `product_siteprice`.`price_id` = `product_price`.`id` '
            'AND site_id=%s', [site.pk]
        )

    queryset = queryset.annotate(**site_annotations)

修改

我的模型看起来像这样简化:

class Site(Model):
    name = models.CharField(_('display name'), max_length=50)


class Price(Model):
    name = models.CharField()


class SitePrice(Model):
    price = models.ForeignKey(Price)
    site = models.ForeignKey(Site)

现在我想要的表是:

 Product | Nr of prices on Site A | Nr of prices on Site B |
 --------|------------------------|------------------------|
 Iphone  | 6                      | 3                      |
 Xperia  | 42                     | 66                     |

我想对价格数量进行排序和过滤,这就是我需要注释的原因。

注意如果你不了解其余的背景,价格有点误导,在这种情况下它可以看作更像产品

2 个答案:

答案 0 :(得分:0)

根据我的理解,您只需要过滤相关网站上的价格,然后获取对象数量的计数。

Price.objects.filter(site_price__site_id=site.pk).count()

虽然您可能只想删除网站价格模型并将其替换为多对多字段

答案 1 :(得分:0)

我认为您想要的查询看起来像这样:

qs = SitePrice.objects.values('price_id', 'site_id').annotate(d_count=Count('id'))

为了获得你想要的表格,你可以将它格式化成一个类似这样的字典:

from collections import defaultdict
values = defaultdict(dict)
for x in qs:
    values[ x['price_id'] ][ x['site_id'] ] = x['d_count']

要打印此表,您可以使用:

price_ids = list(values.keys()) # you don’t need `list` for python 2
site_ids = set()
for x in values.values():
    site_ids |= set(x.keys())
site_ids = list(site_ids)
site_ids.sort()
prices = dict(Price.objects.filter(id__in=price_ids).values_list('id', 'name'))
sites = dict(Site.objects.filter(id__in=site_ids).values_list('id', 'name'))
print('         ', end='') # for python 3
# print '        ', # for python 2
for x in site_ids:
    print('%-8s ' % sites[x], end='')
print('')
for x, counts in values.items():
    print('%-8s ' % prices[x], end='')
    for site_id in site_ids:
        d_count = counts.get(site_id, 0)
        print('%-8s ' % d_count, end='')
    print('')