annotate:
多用于跨表查询,作用于queryset,其实就是给Queryset添加了一个属性,Queryset中的每个对象都会有这么一个属性,属性可以是模型中的字段,也可自定义。
#品牌模型
class Brand(models.Model):
name = models.CharField(max_length=20, unique=True, verbose_name='名称')
location = models.CharField(max_length=30, default='中国', blank=True, verbose_name='品牌所属地区')
logo = models.ImageField(null=True, blank=True, verbose_name='Logo图片')
create_time = models.DateField(auto_now_add=True, verbose_name='创建时间')
#商品模型
class Goods(models.Model):
name = models.CharField(max_length=50, verbose_name='名称')
sales = models.IntegerField(default=0, null=True, blank=True, verbose_name='销量')
comments = models.IntegerField(default=0, null=True, blank=True, verbose_name='评价数')
brand = models.ForeignKey(Brand, null=True, on_delete=models.PROTECT, verbose_name='所属品牌')
create_time = models.DateField(auto_now_add=True, verbose_name='创建日期')
查询每个品牌下对应的商品数量:
#查询每个品牌下的商品数量,结果为一个queryset,并且每个对象都有一个num_count属性,这个属性的值就是每个品牌下的商品数量。
result = Brand.objects.annotate(num_count=Count('goods')) #Sun(类名小写)
result[0].num_count #拿到queryset中第一个对象的num_count属性
#查询 华为 品牌下的商品数量,结果任然是queryset
result = Brand.objects.filter(name='华为').annotate(num_count=Count('goods'))
result[0].num_count #获取num_count属性
#与values合用,相当于按values的值进行分组聚合
result = Brand.objects.values('name').annotate(num_count=Count('goods'))
#结果:
<QuerySet [{'name': 'opoo', 'num_count': 0}, {'name': '华为', 'num_count': 3}, {'name': '小米', 'num_count': 0}, {'name': '苹果', 'num_count': 3}]>
#对应的sql:
SELECT `tb_brand`.`name`, COUNT(`tb_goods`.`id`) AS `num_count` FROM `tb_brand` LEFT OUTER JOIN `tb_goods` ON (`tb_brand`.`id` = `tb_goods`.`brand_id`) GROUP BY `tb_brand`.`name` ORDER BY NULL
result = Brand.objects.values('name', 'location').annotate(num_count=Count('goods'))#按照name和location进行分组(只有当name和location都一样时,才会被视为同一分组)
#结果:
<QuerySet [{'name': 'opoo', 'location': '中国', 'num_count': 0}, {'name': '华为', 'location': '中国', 'num_count': 3}, {'name': '小米', 'location': '中国', 'num_count': 0}, {'name': '苹果', 'location': '美国', 'num_count': 3}]>
#对应的sql:
SELECT `tb_brand`.`first_letter`, `tb_brand`.`location`, COUNT(`tb_goods`.`id`) AS `num_count` FROM `tb_brand` LEFT OUTER JOIN `tb_goods` ON (`tb_brand`.`id` = `tb_goods`.`brand_id`) GROUP BY `tb_brand`.`first_letter`, `tb_brand`.`location` ORDER BY NULL
#查询每个品牌下商品的销量
result = Brand.objects.values('name').annotate(sale_count=Sum('goods__sales')) #类名小写__字段
#添加模型之外的字段
result = Brand.objects.values('name').annotate(a_field=F('goods__sales'), b_filed=Value('default'))
aggregate:
作用于queryset,对某列进行如下操作:
- Sum:求和
- Count:返回数量
- Avg:返回平均值
- Max:求最大值
- Min:求最小值
- Variance:计算方差
- StdDev:计算标准差
#对商品销量取平均值,求和
result = Goods.objects.all().aggregate(avg=Avg('sales'),sum=Sum('sales'))
#结果:
{'avg': 3.625, 'sum': 29}