You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于外键过滤对象?按类别筛选产品并将无类别产品后置

解决方案:按类别分组展示产品并将无类别产品置于末尾

我来帮你搞定这个按类别筛选展示产品的需求,刚好之前做过类似的功能,下面是完整的实现步骤:

1. 先确认模型关系(如果还没定义好的话)

首先确保你的Product模型里的product_type字段是允许为空的外键,关联到ProductCategory:

# models.py
from django.db import models
from django.contrib.auth.models import User

class ProductCategory(models.Model):
    name = models.CharField(max_length=100)
    # 可根据需求添加其他字段,比如描述、排序权重等

    def __str__(self):
        return self.name

class Product(models.Model):
    name = models.CharField(max_length=100)
    user = models.ForeignKey(User, on_delete=models.CASCADE)  # 关联到产品所属用户
    product_type = models.ForeignKey(
        ProductCategory, 
        on_delete=models.SET_NULL, 
        null=True, 
        blank=True,
        verbose_name="产品类别"
    )
    # 其他产品相关字段,比如价格、库存、创建时间等

    def __str__(self):
        return self.name

2. 在视图中处理数据分组与排序

核心是先对产品进行排序(保证有类别的在前,同类别下按产品名称排序),然后按类别分组,最后单独把无类别的产品放到末尾:

# views.py
from django.shortcuts import render
from django.db.models import Case, When, Value, BooleanField
from itertools import groupby
from .models import Product

def user_products(request):
    # 获取当前用户的产品,先按"是否有类别"排序(有类别的在前),再按类别名称、产品名称排序
    user_products = Product.objects.filter(user=request.user).annotate(
        has_category=Case(
            When(product_type__isnull=False, then=Value(True)),
            default=Value(False),
            output_field=BooleanField()
        )
    ).order_by('-has_category', 'product_type__name', 'name')

    # 按类别分组(只处理有类别的产品)
    grouped_products = []
    category_groups = groupby(
        user_products.filter(product_type__isnull=False), 
        key=lambda product: product.product_type
    )
    for category, products in category_groups:
        grouped_products.append({
            'category': category,
            'products': list(products)
        })

    # 添加无类别的产品到列表末尾
    uncategorized = user_products.filter(product_type__isnull=True)
    if uncategorized.exists():
        grouped_products.append({
            'category': None,
            'products': list(uncategorized)
        })

    return render(request, 'products/user_products.html', {'grouped_products': grouped_products})

3. 模板中渲染分组后的产品

在模板里循环分组数据,分别展示每个类别下的产品,最后展示无类别产品:

<!-- templates/products/user_products.html -->
<div class="product-container">
    <h1>我的产品列表</h1>
    {% for group in grouped_products %}
        <div class="category-block">
            <h2>
                {% if group.category %}
                    {{ group.category.name }}
                {% else %}
                    无类别产品
                {% endif %}
            </h2>
            <ul class="product-list">
                {% for product in group.products %}
                    <li>{{ product.name }}</li>
                    <!-- 可根据需求添加更多产品信息,比如价格、编辑/删除按钮等 -->
                {% empty %}
                    <li>暂无产品</li>
                {% endfor %}
            </ul>
        </div>
    {% empty %}
        <p>你还没有添加任何产品</p>
    {% endfor %}
</div>

关键细节说明

  • 排序逻辑:用Case/When给产品标注has_category字段,排序时-has_category确保有类别的产品排在最前面,无类别的自动到末尾
  • 分组注意事项:itertools.groupby要求数据先按分组字段排序,所以我们先按product_type__name排序,这样同类别产品会被分到一组
  • 无类别处理:单独提取无类别产品添加到分组列表最后,严格保证展示顺序符合要求

内容的提问来源于stack exchange,提问作者Ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:06:23