我有一个简单的模型,其中包括产品和类别表。 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
是否有更有效的方法来构建此查询?也许带注释?
答案 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
您不应该在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。