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

Django新手求助:如何用.filter按分类展示商品?

Django按分类展示商品实现方案(带详细解释)

原代码存在的核心问题

  • Product模型中外键字段名Category不符合Python命名规范(应小写),易导致查询逻辑出错
  • Category和Product的slug字段使用CharField不够严谨,缺乏URL友好性与唯一性约束
  • 缺失categoryslug视图实现,这是按分类过滤商品的核心逻辑
  • 模型中__str__方法缩进错误,未包含在类内部

一、修正后的Models代码

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=200)
    # 使用SlugField存储URL友好字符串,unique=True避免分类slug重复
    slug = models.SlugField(max_length=200, unique=True)

    def __str__(self):
        return self.name

class Product(models.Model):
    # 外键字段名改为小写category,符合PEP8规范,related_name方便反向查询商品
    category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='products')
    name = models.CharField(max_length=200, null=False, blank=False)
    slug = models.SlugField(max_length=200, unique=True, null=False, blank=False)
    description = models.TextField(max_length=350, null=False, blank=False)
    # 指定图片存储路径,避免媒体文件混乱
    image = models.ImageField(null=False, blank=False, upload_to='product_images/')
    quantity = models.IntegerField(null=False, blank=False)

    def __str__(self):
        return self.name

关键解释:

  • SlugField:自动去除特殊字符、转为小写,确保URL路径合法;unique=True避免不同分类/商品出现相同slug导致的URL冲突
  • related_name='products':允许通过category.products.all()直接获取该分类下的所有商品,简化查询逻辑
  • upload_to:将商品图片统一存储到media/product_images/目录,需配合Django媒体文件配置使用

二、修正后的URLs代码

from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name="home"),
    # 路径改为语义化的product/,便于理解维护
    path('product/<str:slug>/', views.product_detail, name="product_detail"),
    path('categories/', views.category_list, name="category_list"),
    path('category/<str:slug>/', views.category_products, name="category_products"), 
]

关键解释:

  • 重命名视图与URL名称,语义更清晰:比如fd改为product_detail,categoryslug改为category_products
  • URL末尾添加/:符合Django规范,避免出现category/slug和category/slug/两个重复路径

三、修正后的Views代码

from django.shortcuts import render, get_object_or_404
from .models import Product, Category

def home(request):
    context = {
        'products': Product.objects.all(),
    }
    return render(request, 'pages/home.html', context)

def product_detail(request, slug):
    # 用get_object_or_404替代get(),商品不存在时返回404页面,避免报错
    product = get_object_or_404(Product, slug=slug)
    context = {
        'product': product,
    }
    return render(request, 'pages/product.html', context)

def category_list(request):
    context = {
        'categories': Category.objects.all(),
    }
    return render(request, 'pages/category.html', context)

def category_products(request, slug):
    # 获取指定slug的分类,不存在则返回404
    category = get_object_or_404(Category, slug=slug)
    # 两种方式过滤该分类下的商品,任选其一即可
    # 方式1:正向过滤
    products = Product.objects.filter(category=category)
    # 方式2:利用related_name反向查询(更简洁)
    # products = category.products.all()
    context = {
        'category': category,
        'products': products,
    }
    return render(request, 'pages/category_products.html', context)

关键解释:

  • get_object_or_404:比objects.get()更健壮,查询不到对象时自动返回404错误,避免抛出DoesNotExist异常
  • category_products视图核心逻辑:通过分类slug定位分类对象,再用filter筛选该分类下的所有商品,两种查询方式均有效

四、模板示例(category_products.html)

<h1>{{ category.name }}</h1>
<div class="product-list">
    {% for product in products %}
        <div class="product-item">
            <img src="{{ product.image.url }}" alt="{{ product.name }}">
            <h3><a href="{% url 'product_detail' product.slug %}">{{ product.name }}</a></h3>
            <p>{{ product.description }}</p>
            <p>库存:{{ product.quantity }}</p>
        </div>
    {% empty %}
        <p>该分类下暂无商品</p>
    {% endfor %}
</div>

关键解释:

  • 用{{ category.name }}展示当前分类名称
  • {% for %}循环遍历分类商品,点击商品名称可跳转到详情页
  • {% empty %}处理分类无商品的边界情况,给出友好提示

后续必要操作

  1. 数据库迁移:修改模型后执行以下命令更新数据库:
python manage.py makemigrations
python manage.py migrate
  1. 媒体文件配置:在项目settings.py中添加:
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'

并在项目根URL中添加媒体文件路由:

from django.conf import settings
from django.conf.urls.static import static

urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 19:40:30