在DRF中过滤嵌套视图,如何实现?
Filtering nested views in DRF, how to implement?
有一个产品序列化程序:
class ProductSerializer(serializers.ModelSerializer):
category = serializers.SlugRelatedField(slug_field="name", read_only=True)
class Meta:
model = Product
fields=(
'id',
'name',
'category',
'subcategory',
'manufacturer',
'get_absolute_url',
'description',
'price',
'get_image',
'get_thumbnail'
)
以及生成与此类别关联的产品的嵌套表示的类别序列化程序:
class CategorySerializer(serializers.ModelSerializer):
products = ProductSerializer(many=True)
class Meta:
model = Category
fields = (
'id',
'name',
'get_absolute_url',
'products'
)
示例数据:
[
{
"id": 4,
"name": "Notebook",
"get_absolute_url": "/notebooks/",
"products": [
{
"id": 3,
"name": "HP for work",
"category": "Notebook",
"subcategory": "Working",
"manufacturer": "HP",
"get_absolute_url": "/notebooks/hp_2000/",
"description": "desc",
"price": "25000.00",
"get_image": "http://127.0.0.1:8000/media/uploads/slidebar-image1.jpg",
"get_thumbnail": "http://127.0.0.1:8000/media/uploads/uploads/slidebar-image1.jpg"
},
{
"id": 1,
"name": "Acer for game",
"category": "Notebook",
"subcategory": "Gamers",
"manufacturer": "Acer",
"get_absolute_url": "/notebooks/acer_for_game/",
"description": "Desc",
"price": "50000.00",
"get_image": "http://127.0.0.1:8000/media/uploads/AcerAspire_6m9A45R.jpg",
"get_thumbnail": "http://127.0.0.1:8000/media/uploads/uploads/AcerAspire_6m9A45R.jpg"
}
]
}
]
我还可以使用查询参数在 URL 中显示过滤后的产品,例如,按子类别:
url = http://127.0.0.1:8000/api/products/query-product/?sub=Gamers:
[
{
"id": 1,
"name": "Acer for game",
"category": "Notebook",
"subcategory": "Gamers",
"manufacturer": "Acer",
"get_absolute_url": "/notebooks/acer_for_game/",
"description": "Desc",
"price": "50000.00",
"get_image": "http://127.0.0.1:8000/media/uploads/AcerAspire_6m9A45R.jpg",
"get_thumbnail": "http://127.0.0.1:8000/media/uploads/uploads/AcerAspire_6m9A45R.jpg"
}
]
这是过滤产品的地方:
class ProductQueryList(generics.ListAPIView):
serializer_class = ProductSerializer
def get_queryset(self):
queryset = Product.objects.all()
subcategory_name = self.request.query_params.get('sub')
if subcategory_name is not None:
queryset = queryset.filter(subcategory = subcategory_name)
return queryset
我目前无法过滤类别。在这里,我要么传递一个包含特定类别的 queryset
,要么将与该类别关联的筛选产品传递给相同的 queryset
:
class CategoryDetail(generics.ListAPIView):
serializer_class = CategorySerializer
def get_queryset(self):
category = self.kwargs['category_slug']
# queryset = Category.objects.get(slug=category)
# subcategory_name = self.request.query_params.get('sub')
# # if subcategory_name is not None:
# queryset = queryset.products.filter(subcategory = subcategory_name)
return Category.objects.filter(slug=category)
有什么方法可以将 queryset.products
之类的内容传递给嵌套产品列表吗?那些以某种方式将类别传递给 queryset
,并覆盖嵌套在其中的产品。
你可以在这里使用一个Prefetch
对象来实现嵌套过滤,像这样:
class CategoryDetail(generics.ListAPIView):
serializer_class = CategorySerializer
def get_queryset(self):
category = self.kwargs['category_slug']
queryset = Category.objects.get(slug=category)
subcategory_name = self.request.query_params.get('sub')
if subcategory_name is not None:
prefetch_filtered_products = Prefetch(
'products',
Product.objects.filter(subcategory=subcategory_name)
)
return queryset.prefetch_related(prefetch_filtered_products)
return queryset.prefetch_related('products')
这还可以避免您对数据库进行额外查询。
有一个产品序列化程序:
class ProductSerializer(serializers.ModelSerializer):
category = serializers.SlugRelatedField(slug_field="name", read_only=True)
class Meta:
model = Product
fields=(
'id',
'name',
'category',
'subcategory',
'manufacturer',
'get_absolute_url',
'description',
'price',
'get_image',
'get_thumbnail'
)
以及生成与此类别关联的产品的嵌套表示的类别序列化程序:
class CategorySerializer(serializers.ModelSerializer):
products = ProductSerializer(many=True)
class Meta:
model = Category
fields = (
'id',
'name',
'get_absolute_url',
'products'
)
示例数据:
[
{
"id": 4,
"name": "Notebook",
"get_absolute_url": "/notebooks/",
"products": [
{
"id": 3,
"name": "HP for work",
"category": "Notebook",
"subcategory": "Working",
"manufacturer": "HP",
"get_absolute_url": "/notebooks/hp_2000/",
"description": "desc",
"price": "25000.00",
"get_image": "http://127.0.0.1:8000/media/uploads/slidebar-image1.jpg",
"get_thumbnail": "http://127.0.0.1:8000/media/uploads/uploads/slidebar-image1.jpg"
},
{
"id": 1,
"name": "Acer for game",
"category": "Notebook",
"subcategory": "Gamers",
"manufacturer": "Acer",
"get_absolute_url": "/notebooks/acer_for_game/",
"description": "Desc",
"price": "50000.00",
"get_image": "http://127.0.0.1:8000/media/uploads/AcerAspire_6m9A45R.jpg",
"get_thumbnail": "http://127.0.0.1:8000/media/uploads/uploads/AcerAspire_6m9A45R.jpg"
}
]
}
]
我还可以使用查询参数在 URL 中显示过滤后的产品,例如,按子类别:
url = http://127.0.0.1:8000/api/products/query-product/?sub=Gamers:
[
{
"id": 1,
"name": "Acer for game",
"category": "Notebook",
"subcategory": "Gamers",
"manufacturer": "Acer",
"get_absolute_url": "/notebooks/acer_for_game/",
"description": "Desc",
"price": "50000.00",
"get_image": "http://127.0.0.1:8000/media/uploads/AcerAspire_6m9A45R.jpg",
"get_thumbnail": "http://127.0.0.1:8000/media/uploads/uploads/AcerAspire_6m9A45R.jpg"
}
]
这是过滤产品的地方:
class ProductQueryList(generics.ListAPIView):
serializer_class = ProductSerializer
def get_queryset(self):
queryset = Product.objects.all()
subcategory_name = self.request.query_params.get('sub')
if subcategory_name is not None:
queryset = queryset.filter(subcategory = subcategory_name)
return queryset
我目前无法过滤类别。在这里,我要么传递一个包含特定类别的 queryset
,要么将与该类别关联的筛选产品传递给相同的 queryset
:
class CategoryDetail(generics.ListAPIView):
serializer_class = CategorySerializer
def get_queryset(self):
category = self.kwargs['category_slug']
# queryset = Category.objects.get(slug=category)
# subcategory_name = self.request.query_params.get('sub')
# # if subcategory_name is not None:
# queryset = queryset.products.filter(subcategory = subcategory_name)
return Category.objects.filter(slug=category)
有什么方法可以将 queryset.products
之类的内容传递给嵌套产品列表吗?那些以某种方式将类别传递给 queryset
,并覆盖嵌套在其中的产品。
你可以在这里使用一个Prefetch
对象来实现嵌套过滤,像这样:
class CategoryDetail(generics.ListAPIView):
serializer_class = CategorySerializer
def get_queryset(self):
category = self.kwargs['category_slug']
queryset = Category.objects.get(slug=category)
subcategory_name = self.request.query_params.get('sub')
if subcategory_name is not None:
prefetch_filtered_products = Prefetch(
'products',
Product.objects.filter(subcategory=subcategory_name)
)
return queryset.prefetch_related(prefetch_filtered_products)
return queryset.prefetch_related('products')
这还可以避免您对数据库进行额外查询。