通过过滤对象列表来过滤对象列表

时间:2017-01-29 08:09:29

标签: django django-rest-framework django-queryset django-filters

我有两个模型ItemCategory和Item,我想通过过滤 is_published 项目字段来过滤ItemCategory列表。

class ItemCategory(models.Model):
    category_name = models.CharField(max_length=50, unique=True)
    category_image = models.ImageField(upload_to='item-category', null=True)

    def __str__(self):
        return 'category: ' + self.category_name


class Item(models.Model):
    item_name = models.CharField(max_length=50)
    item_desc = models.CharField(max_length=500, blank=True)
    price = models.FloatField()

    item_image = models.ImageField(upload_to='item-images')
    num_of_items_available = models.IntegerField()

    category_name = models.ForeignKey(ItemCategory, on_delete=models.CASCADE, null=True, related_name='items')
    is_published = models.BooleanField(default=False)

    def __str__(self):
        return 'item: ' + self.item_name

这是我的方法,但没有取得任何成功。

class ItemCategoryView(viewsets.ViewSet):
    permission_classes = (AllowAny,)
    serializer_class = ItemCategoryListSerializer

    def list(self, request, format=None):

        queryset = ItemCategory.objects.filter(items__in=Item.objects.filter(is_published=True))

        serializer = ItemCategorySerializer(queryset, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

ItemCategorySerializer看起来像这样

class ItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = Item
        fields = ('pk', 'item_name', 'item_desc', 'price', 'item_image', 'num_of_items_available',
              'category_name', 'is_published')


class ItemCategorySerializer(serializers.ModelSerializer):
    items = ItemSerializer(many=True, read_only=True)

    class Meta:
        model = ItemCategory
        fields = ('pk', 'category_name', 'category_image',  'items')

有谁能告诉我如何处理这个问题?

修改

我尝试了这两个查询

  

queryset = ItemCategory.objects.filter(items__in = Item.objects.filter(is_published = True))queryset = ItemCategory.objects.filter(items__is_published = True)

我认为这个查询都有效,但不是我想要的方式。下面是它如何运作。

返回ItemCategory列表,其中 is_published = True的项目列表。说有3个类别(A,B,C),每个类别有3个项目列表(A1,A2,A3,B1,B2,B3,C1,C2,C3)。除C3外,让所有人都 is_published = False。

所以现在查询结果是这样的。它仅返回C类别,包含所有列表项C1,C2,C3。这不是理想的结果。我应该只获得C3,因为这是唯一发布的项目。

2 个答案:

答案 0 :(得分:1)

您可以使用filterprefetch_related

来实现这一目标
queryset = ItemCategory.objects.filter(items__is_published=True).prefet‌​ch_related(Prefetch(‌​"items", queryset=Item.objects.fiter(is_published=True))

答案 1 :(得分:0)

我认为你需要在返回类别本身之前过滤它们。

  1. 过滤所有已发布的项目。
  2. 按发布的项目过滤所有类别。
  3. 也许您可以使用此方法,但之前我建议您使用QuerySet经理。

    <强> 1。 models.py

    class ItemCategory(models.Model):
        category_name = models.CharField(max_length=50, unique=True)
        category_image = models.ImageField(upload_to='item-category', null=True)
    
        def get_published_items(self):
            """
            return all items contains with this single Category.
            """
            return Item.objects.published().filter(category_name__pk=self.pk)
    
        def __str__(self):
            return 'category: ' + self.category_name
    
    
    class ItemQuerySet(models.QuerySet):
    
        def published(self):
            return self.filter(is_published=True)
    
        def unpublished(self):
            return self.filter(is_published=False)
    
    
    class Item(models.Model):
        ....
        category_name = models.ForeignKey(
          ItemCategory, on_delete=models.CASCADE, 
          null=True, related_name='items')
        is_published = models.BooleanField(default=False)
    
        objects = ItemQuerySet.as_manager()
    
        def __str__(self):
            return 'item: ' + self.item_name
    

    <强> 2。 views.py

    class ItemCategoryView(viewsets.ViewSet):
        permission_classes = (AllowAny,)
        serializer_class = ItemCategoryListSerializer
    
        def list(self, request, format=None):
            # find all categories first
            published_categories_by_items = [ c.category_name for c in Item.objects.published() ]
            # then, filter the categories itself.
            queryset = ItemCategory.objects.filter(pk__in=[ c.pk for c in published_categories_by_items]).distinct()
    
            serializer = ItemCategorySerializer(queryset, many=True)
            return Response(serializer.data, status=status.HTTP_200_OK)