ForeignKey 元素的 Django Queryset 过滤器
Django Queryset filter for ForeignKey elements
我在我的一个视图中构建自定义查询集时遇到问题。
这是我的模型的简化版本。这个想法是我想跟踪不同商店中不同产品的价格。一个商店可以有多个产品,一个产品可以出现在多个商店。产品可以设置 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']
最后,这里是相应的 view,我想在其中使用 custom queryset:
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()
功能。这就是我实际正在做的事情,我不知道如何继续。
我想要实现的是 control with the is_special
attribute,if special products should be part of the output or not.
这是我想要的输出的两个示例(属性 is_special
实际上没有显示在这里,但假设名称方案 "Special Product XY" 的产品有is_special
设置为 True
)
我正在寻找两个不同的查询集:
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)
实际上 returns 所有至少有一个 is_special=True
产品的商店
queryset = Shop.objects.filter(shopproductpricedata__product__is_special=True)
returns 所有至少有一种 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)))
尝试使用 prefetch_related
so that the related fields are already fetched, using 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)))
我在我的一个视图中构建自定义查询集时遇到问题。
这是我的模型的简化版本。这个想法是我想跟踪不同商店中不同产品的价格。一个商店可以有多个产品,一个产品可以出现在多个商店。产品可以设置 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']
最后,这里是相应的 view,我想在其中使用 custom queryset:
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()
功能。这就是我实际正在做的事情,我不知道如何继续。
我想要实现的是 control with the is_special
attribute,if special products should be part of the output or not.
这是我想要的输出的两个示例(属性 is_special
实际上没有显示在这里,但假设名称方案 "Special Product XY" 的产品有is_special
设置为 True
)
我正在寻找两个不同的查询集:
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)
实际上 returns 所有至少有一个 is_special=True
产品的商店
queryset = Shop.objects.filter(shopproductpricedata__product__is_special=True)
returns 所有至少有一种 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)))
尝试使用 prefetch_related
so that the related fields are already fetched, using 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)))