Django ORM使用子查询进行注释

时间:2018-03-17 20:45:59

标签: python django django-orm

我有以下型号:

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

class Goods(models.Model):
   store = models.ForeigKey(Store, on_delete=models.CASCADE)
   total_cost = models.DecimalField()
   different values ...

所以,我根据参数过滤了所有商品,现在我的目标是从每个商店中获得一件商品,其中商店中其他商品的价格最低

stores = Store.objects.all() - all stores
goods = Good.objects.filter(..) - filter goods

goods.annotate(min_price=Subquery(Min(stores.values('goods__total_cost'))))                                                                   

我试过这样的事情,但是我有一个错误:

AttributeError: 'Min' object has no attribute 'query'

1 个答案:

答案 0 :(得分:1)

我认为在你的上下文中,你需要Group By特征而不是Django注释,
来自this SO answer

>>> q = Book.objects.annotate(num_authors=Count('authors'))
>>> q[0].num_authors
2
>>> q[1].num_authors
1

q是书籍的查询集,但每本书都注明了作者的数量。 也就是说,如果您annotate goods min_price个查询集,它们将不会返回某些已排序/已过滤的对象集。它将仅使用新字段Group By进行注释。

因此我建议您执行from django.db.models import Min result = Goods.objects.values('store').annotate(min_val=Min('total_cost')) 操作,如下所示

In [2]: from django.db.models import Min

In [3]: Goods.objects.values('store').annotate(min_val=Min('total_cost'))
Out[3]: <QuerySet [{'store': 1, 'min_val': 1}, {'store': 2, 'min_val': 2}]>

In [6]: Goods.objects.annotate(min_val=Min('total_cost'))
Out[6]: <QuerySet [<Goods: Goods object>, <Goods: Goods object>, <Goods: Goods object>, <Goods: Goods object>, <Goods: Goods object>]>

In [7]: Goods.objects.annotate(min_val=Min('total_cost'))[0].__dict__
Out[7]:
{'_state': <django.db.models.base.ModelState at 0x7f5b60168ef0>,
 'id': 1,
 'min_val': 1,
 'store_id': 1,
 'total_cost': 1}

In [8]: Goods.objects.annotate(min_val=Min('total_cost'))[1].__dict__
Out[8]:
{'_state': <django.db.models.base.ModelState at 0x7f5b6016af98>,
 'id': 2,
 'min_val': 123,
 'store_id': 1,
 'total_cost': 123}


示例

from django.db.models import Min

store_list = Store.objects.values_list('id', flat=True)  # list of id's od Store instance
result_queryset = []
for store_id in store_list:
    min_value = Goods.objects.filter(store_id=store_id).aggregate(min_value=Min('total_cost'))
    result_queryset = result_queryset|Goods.objects.filter(store_id=store_id, total_cost=min_value)



UPDATE-1
我认为,这不是一个好主意,可能会出现一些优化问题,但如果您需要,可以试试

Update-1



UPDATE-2

我认为我的goods_queryset = Goods.objects.filter(**you_possible_filters) result = goods_queryset.filter(store_id__in=[good['store'] for good in Goods.objects.values('store').annotate(min_val=Min('total_cost'))]) 部分存在大量的性能问题,所以我找到了一个可能的问题答案,即

Collection.belongsTo(models.User, {
          onDelete: 'CASCADE'
          foreignKey: 'myCustomUserId'
        })