Django中如何根据Product的Attribute属性筛选商品
模型关联优化(可选但推荐)
先给ProductAttribute的外键添加反向关联名,方便后续跨表查询:
class ProductAttribute(models.Model): # 新增related_name,后续Product可直接通过attributes访问关联的属性 product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='attributes') # 其余字段保持原有逻辑不变 size = models.ForeignKey(Size, on_delete=models.CASCADE, null=True, blank=True) price = models.DecimalField(max_digits=10, decimal_places=2, validators=[MinValueValidator(1)]) discounted_price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True) stock = models.CharField(max_length=10, null=True)
编写django_filters筛选器类
import django_filters from .models import Product, Size class ProductFilter(django_filters.FilterSet): # 单尺码筛选:传尺码ID查询对应商品 size = django_filters.ModelChoiceFilter( queryset=Size.objects.all(), field_name='attributes__size', # 跨反向关联查询属性的size字段 label='尺码', distinct=True # 避免同一商品关联多个属性时返回重复结果 ) # 可选配置1:多尺码同时筛选,支持传多个尺码ID查询 # size = django_filters.ModelMultipleChoiceFilter( # queryset=Size.objects.all(), # field_name='attributes__size', # lookup_expr='in', # label='多尺码筛选', # distinct=True # ) # 可选配置2:直接传尺码值(如M/XL)筛选,前提是Size模型有存储尺码值的name字段 # size_name = django_filters.CharFilter( # field_name='attributes__size__name', # lookup_expr='exact', # label='尺码值', # distinct=True # ) class Meta: model = Product # 可按需添加其他需要筛选的字段,如分类、品牌、状态等 fields = ['category', 'brand', 'status', 'size']
视图中使用筛选器
普通Django视图场景
from .filters import ProductFilter def product_list(request): product_query = Product.objects.filter(status='Active') # 传入GET参数和查询集完成筛选 filter_obj = ProductFilter(request.GET, queryset=product_query) # 筛选后的商品结果存储在filter_obj.qs中 return render(request, 'product/list.html', {'products': filter_obj.qs, 'filter': filter_obj})
Django REST Framework视图场景
from rest_framework import viewsets from .models import Product from .filters import ProductFilter from .serializers import ProductSerializer class ProductViewSet(viewsets.ReadOnlyModelViewSet): queryset = Product.objects.filter(status='Active') serializer_class = ProductSerializer filterset_class = ProductFilter # 直接指定筛选器类即可生效
注意事项
distinct=True参数必须添加,跨一对多关联查询时,符合条件的关联属性有多条的话会返回重复的商品记录,该参数会自动完成去重。- 后续如果要新增颜色等其他商品属性,只要在
ProductAttribute模型里加对应的外键字段,然后在筛选器里参照尺码的写法新增对应筛选字段即可。
内容的提问来源于stack exchange,提问作者Kuldeep
相关产品推荐
相关产品推荐

