【问题标题】:Django Queryset filter for ForeignKey elementsForeignKey 元素的 Django Queryset 过滤器
【发布时间】:2021-05-13 02:57:44
【问题描述】:

在我的一个视图中构建自定义查询集时遇到问题。

这是我的模型的简化版本。这个想法是我想跟踪不同商店中不同产品的价格。 一个商店可以有多个产品,一个产品可以出现在多个商店。产品可以设置is_special 标志来突出显示它们。选择以下结构是因为它可以轻松地允许以后添加新产品和商店:

class Product(models.Model):
    product_id = models.CharField(max_length=255, primary_key=True)
    is_special = models.BooleanField(default=False)
    product_name = models.CharField(max_length=255, default='', blank=False, null=False)

class ShopProductPrice(models.Model):
    product = models.ForeignKey("Product", on_delete=models.CASCADE)
    shop = models.ForeignKey("Shop", on_delete=models.CASCADE, related_name="shop_entry")
    price = models.FloatField(default=0.0, null=False)

class Shop(models.Model):
    name = models.CharField(max_length=255, default='', blank=False, null=False)
    location = models.CharField(max_length=255, default='', blank=False, null=False)

这些是我的序列化器

class ShopProductPriceSerializer(serializers.ModelSerializer):
    class Meta:
        model = ShopProductPrice
        fields = ['product', 'price']

class ShopSerializer(serializers.ModelSerializer):
    shopProductPriceData = ShopProductPriceSerializer(many=True, source='shopProductPrice_set')

    class Meta:
        model = Shop
        fields = ['name', 'location', 'shopProductPriceData']

最后,这是我想在其中使用自定义查询集的相应视图

class ShopViewSet(viewsets.ModelViewSet):
    queryset = Shop.objects.all()
    serializer_class = ShopSerializer

    def get_queryset(self):
        queryset = Shop.objects.filter(shopproductpricedata__product__is_special=False)
        return queryset

重点现在是get_queryset() 函数。这就是我实际正在做的事情,我不知道如何继续。 我想要实现的是使用is_special 属性控制特殊产品是否应该是输出的一部分。

这是我想要的输出的两个示例(属性 is_special 实际上没有显示在这里,但假设名称方案 "Special Product XY" 的产品将 is_special 设置为 @987654329 @)

我正在寻找两个不同的查询集:

1:特殊产品隐藏在输出中的查询集(shopProductPriceData 中没有元素的商店也不应包括在内)

[
    {
        "name": "Shop A",
        "location": "New York",
        "shopProductPriceData": [
            {
                "product_name": "Product 2",
                "price": 100.0
            }
        ]
    },
    {
        "location": "Shop B",
        "date": "Berlin",
        "shopProductPriceData": [
            {
                "product_name": "Product 3",
                "price": 100.0
            }
        ]
    }
]

2:包含特殊产品的查询集:

[
    {
        "name": "Shop A",
        "location": "New York",
        "shopProductPriceData": [
            {
                "product_name": "Special Product 1",
                "price": 5.0
            },
            {
                "product_name": "Product 2",
                "price": 100.0
            }
        ]
    },
    {
        "location": "Shop B",
        "date": "Berlin",
        "shopProductPriceData": [
            {
                "product_name": "Special Product 1",
                "price": 8.0
            },
            {
                "product_name": "Product 3",
                "price": 100.0
            },
            {
                "product_name": "Special Product 2",
                "price": 100.0
            }
        ]
    }
]

但是,对于我上面给出的查询集,这是行不通的:

queryset = Shop.objects.filter(shopproductpricedata__product__is_special=True)实际上返回所有至少有一个is_special=True产品的商店

queryset = Shop.objects.filter(shopproductpricedata__product__is_special=True) 返回所有至少有一个is_special=False 产品的商店。

在这两种情况下,如果显示商店,所有嵌套产品也会显示,无论它们是否是特殊产品。

你能帮我想出一个自定义查询集生成器来产生我想要的输出吗?


编辑:这是可行的解决方案:

queryset = Shop.objects.filter(shopproductpricedata__product__is_special=False).prefetch_related(
     Prefetch('shopProductPrice_set', queryset=ShopProductPrice.objects.filter(product__is_special=False)))

【问题讨论】:

    标签: django django-views django-queryset


    【解决方案1】:

    尝试使用prefetch_related,以便已经获取相关字段,使用Prefetch,您还可以过滤相关对象。

    from django.db.models import Prefetch
    
    queryset = Shop.objects.filter(shopproductpricedata__product__is_special=False).prefetch_related(
        Prefetch('shopproductpricedata__product', queryset=Product.objects.filter(is_special=False)))
    

    【讨论】:

    • 这使我找到了实际的解决方案。太感谢了。我不得不做一些改变。正确的解决方案是:queryset = Shop.objects.filter(shopproductpricedata__product__is_special=False).prefetch_related(Prefetch('shopProductPrice_set', queryset=ShopProductPrice.objects.filter(product__is_special=False)))这将只返回所有商店的非特殊产品。
    猜你喜欢
    • 2014-07-13
    • 2013-09-08
    • 2018-10-09
    • 1970-01-01
    • 2022-11-12
    • 2021-06-16
    • 2011-03-04
    • 2016-07-21
    • 2020-12-24
    相关资源
    最近更新 更多