我有一个非常简单(乍一看)的问题。案例 - 一种产品可以在多个地方(商店)销售,并且每种产品都可以在具有不同类别和子类别的单个商店中表示(这就是为什么类别通过foreignkey与分类链接两次)。 这是我的分类模型,有几个 FK。
class Assortment(models.Model):
category = models.ForeignKey('category.Category', null=True, blank=True, default=None,related_name='assortment_child')
parent_category = models.ForeignKey('category.Category', null=True, blank=True, default=None,related_name='assortment_parent')
product = models.ForeignKey(Product)
shop = models.ForeignKey(Shop)
View ,基于rest_framework.generics.ListAPIView
class InstitutionTreeCategories(generics.ListAPIView):
"""Resource to get shop's tree of categories."""
serializer_class = serializers.InstitutionCategoriesSerializer
def get_queryset(self):
shop = self.get_shop()
return Category.objects.filter(assortment_parent__shop=shop).distinct()
最后,序列化器
class CategoryListSerializer(serializers.ModelSerializer):
class Meta:
"""Meta class."""
model = Category
fields = ('id', 'name', 'image')
class CategoriesTreeSerializer(CategoryListSerializer):
# childs = CategoryListSerializer(many=True, source='assortment_child__parent_category')
childs = serializers.SerializerMethodField()
class Meta(CategoryListSerializer.Meta):
"""Meta class."""
fields = ('id', 'name', 'image', 'childs')
def get_childs(self, obj):
qs = Category.objects.filter(assortment_child__parent_category=obj.id).distinct()
return CategoryListSerializer(qs, many=True, context=self.context).data
我需要使用我的 API 显示单个商店的类别树。
但问题是 - 如果我使用serializer.SerializerMethodField - 它可以工作,但是查询太多(对于每个父类别)。我尝试使用“源”选项和“CategoryListSerializer”来避免它,但我无法做到。每次,我都会得到 - 'Category' object has no attribute assortment_child__parent_category
。在我尝试过的外壳模型中
In [8]: cat.assortment_parent.values('category').distinct()
Out[8]: (0.003) SELECT DISTINCT "marketplace_assortment"."category_id" FROM "marketplace_assortment" WHERE "marketplace_assortment"."parent_category_id" = 4 LIMIT 21; args=(4,)
<AssortmentQuerySet [{'category': 3}]>
所以 - 类别对象有这个属性,当然有,我用了它的 get_childs 方法。所以问题是 - 我如何将它与serializer.ModelSerializer 及其源选项一起使用? (当然使用 select_lated 方法和查询集,以避免过多的查询)。
最佳答案
根据源选项,您应该使用 .
而不是 __
:
childs = CategoryListSerializer(many=True, source='assortment_child.parent_category')
但您仍然会有很多疑问,要修复它,您应该使用 prefetch-related
def get_queryset(self):
shop = self.get_shop()
qs = Category.objects.filter(assortment_parent__shop=shop).all()
return qs.prefetch_related('assortment_child').distinct()
更多详细信息,您可以阅读 how-can-i-optimize-queries-django-rest-framework
关于Django Rest Framework 类别和子级在一个模型中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51010114/