【问题标题】:filter list of objects by filtering a list of objects通过过滤对象列表来过滤对象列表
【发布时间】:2017-06-14 14:30:04
【问题描述】:

我有两个模型ItemCategory和Item,我想通过过滤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)。并让所有 is_published = False 除了 C3。

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

【问题讨论】:

  • 试试这个:queryset = ItemCategory.objects.filter(items__is_published=True) 这个返回 ItemCategory 和已发布的项目。
  • 不,它没有。我试过了
  • 奇怪.. 任何错误或它工作但不返回你想要的?
  • 嘿@neverwalkaloner 它有效。非常感谢
  • 不客气!我将其发布为答案。

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


【解决方案1】:

您可以通过filterprefetch_related 实现此目的:

queryset = ItemCategory.objects.filter(items__is_published=True).prefet‌​ch_related(Prefetch(‌​"items", queryset=Item.objects.fiter(is_published=True))

【讨论】:

    【解决方案2】:

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

    1. 过滤所有已发布的项目。
    2. 按已发布项目过滤所有类别。

    也许你可以使用这种方法,但之前我建议你使用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。 view.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)
    

    【讨论】:

      猜你喜欢
      • 2015-03-24
      • 2022-01-12
      • 2021-09-26
      • 2011-01-10
      • 2013-04-10
      • 1970-01-01
      • 1970-01-01
      • 2018-01-17
      相关资源
      最近更新 更多