Tastypie Dehydrate反向关系计数

时间:2013-01-11 20:49:29

标签: python django tastypie

我有一个简单的模型,其中包括产品和类别表。 Product模型具有外键类别。

当我进行tastypie API调用时返回类别列表/ api / vi / categories / 我想添加一个字段来确定“产品数量”/具有给定类别的产品数量。结果将是:

category_objects[
{ 
   id: 53
   name: Laptops
   product_count: 7
}, 
...
 ]

以下代码正在运行,但我的数据库上的重击很重

    def dehydrate(self, bundle):
        category = Category.objects.get(pk=bundle.obj.id)
        products = Product.objects.filter(category=category)
        bundle.data['product_count'] = products.count()
        return bundle  

是否有更有效的方法来构建此查询?也许带注释?

2 个答案:

答案 0 :(得分:4)

您可以使用QuerSet的{​​{3}}方法来反转select_related。

Asper文档,

  

prefetch_related(*查找)

     

返回自动生成的QuerySet   在单个批次中检索每个指定的相关对象   查找。

     

这与select_related的目的相似,两者都是   旨在阻止由此引起的数据库查询的泛滥   访问相关对象,但策略完全不同。

如果您将脱水功能更改为以下,则数据库将被单击一次。

def dehydrate(self, bundle):
    category = Category.objects.prefetch_related("product_set").get(pk=bundle.obj.id)
    bundle.data['product_count'] = category.product_set.count()
    return bundle 

更新1

您不应该在dehydrate函数内初始化queryset。 queryset应始终仅在Meta类中设置。请查看django-tastypie文档中的以下示例。

class MyResource(ModelResource):
    class Meta:
        queryset = User.objects.all()
        excludes = ['email', 'password', 'is_staff', 'is_superuser']

    def dehydrate(self, bundle):
        # If they're requesting their own record, add in their email address.
        if bundle.request.user.pk == bundle.obj.pk:
            # Note that there isn't an ``email`` field on the ``Resource``.
            # By this time, it doesn't matter, as the built data will no
            # longer be checked against the fields on the ``Resource``.
            bundle.data['email'] = bundle.obj.email

        return bundle

根据django-tastypie函数上的官方dehydrate() prefetch_related

  

<强>脱水物

     

脱水方法需要一个现已完全填充的bundle.data&amp;使   任何最后的改动。这对于一段数据很有用   可能依赖于多个领域,如果你想要额外的推动   不值得拥有自己的字段或者如果你想要的数据   动态删除要返回的数据中的内容。

dehydrate()仅用于对bundle.data进行任何最后的更改。

答案 1 :(得分:2)

您的代码会为每个类别执行额外的计数查询。你对annotate在这类问题上有所帮助你是对的。

Django将在GROUP BY语句中包含所有queryset的字段。请注意.values()和空.group_by()将限制字段设置为必填字段。

cat_to_prod_count = dict(Product.objects
                                .values('category_id')
                                .order_by()
                                .annotate(product_count=Count('id'))
                                .values_list('category_id', 'product_count'))

以上dict对象是地图[category_id - &gt; PRODUCT_COUNT]。

可以在dehydrate方法中使用:

 bundle.data['product_count'] = cat_to_prod_count[bundle.obj.id]

如果这没有用,请尝试在类别记录上保留类似的计数器,并使用singals使其保持最新状态。

注意类别通常是树状生物,您可能也希望保留所有子类别的数量。

在这种情况下,请查看包django-mptt