DRF中通过Category路由过滤关联Product对象的实现方案
解决方案
要实现分类详情接口通过查询参数过滤返回对应产品的通用逻辑,无需为每个分类硬编码规则,可通过重写分类视图的retrieve方法实现,具体步骤如下:
1. 修改分类视图(categories/views.py)
导入所需依赖,重写retrieve方法,根据请求是否携带过滤参数,动态返回分类数据或过滤后的产品数据:
from rest_framework.response import Response from products.serializers import ProductSerializer from .models import Category class CategoriesAPIViewSet(viewsets.ModelViewSet): """ Standard ModelViewSet which implements CRUD with minor changes. """ queryset = Category.objects.all() serializer_class = CategorySerializer lookup_field = 'slug' def retrieve(self, request, *args, **kwargs): instance = self.get_object() filter_params = request.query_params # 存在查询参数时,返回过滤后的产品 if filter_params: # 查询当前分类下的所有产品 products_queryset = instance.products.all() # 处理brand参数(按品牌slug过滤,可根据需求改为按name过滤) if 'brand' in filter_params: brand_slug = filter_params['brand'] products_queryset = products_queryset.filter(brand__slug=brand_slug) # 可扩展其他过滤参数(如price、stock等)的处理逻辑 serializer = ProductSerializer(products_queryset, many=True) return Response(serializer.data) # 无查询参数时,返回原分类及子分类数据 serializer = self.get_serializer(instance) return Response(serializer.data)
2. 可选:包含子分类产品过滤
如果需要返回当前分类及其所有子分类下的产品,利用MPTT的get_descendants方法扩展查询范围:
# 在retrieve方法的filter_params判断内,替换products_queryset的初始化代码 from products.models import Product category_ids = [instance.id] + list(instance.get_descendants().values_list('id', flat=True)) products_queryset = Product.objects.filter(category_id__in=category_ids)
3. 通用过滤扩展(进阶)
如果需要支持更多类型的过滤参数(如价格区间、库存状态等),可以使用django-filter简化逻辑:
- 安装依赖:
pip install django-filter - 在项目
settings.py的INSTALLED_APPS中添加'django_filters' - 定义过滤规则并在视图中使用:
# 在products/views.py或单独的filters.py中定义过滤规则 from django_filters.rest_framework import FilterSet, filters from products.models import Product class ProductFilter(FilterSet): brand = filters.CharFilter(field_name='brand__slug', lookup_expr='exact') min_price = filters.NumberFilter(field_name='price', lookup_expr='gte') max_price = filters.NumberFilter(field_name='price', lookup_expr='lte') class Meta: model = Product fields = ['brand', 'min_price', 'max_price'] # 修改CategoriesAPIViewSet的retrieve方法中的过滤逻辑 filterset = ProductFilter(filter_params, queryset=products_queryset) products_queryset = filterset.qs
这样无论访问哪个分类的详情接口,只要携带对应的查询参数,都会返回符合条件的产品,完全实现通用适配。
内容的提问来源于stack exchange,提问作者Antony_K
相关产品推荐
相关产品推荐

