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

Django新手求助:如何按主分类分组展示对应产品

问题解决:Django按「分类名称+对应产品列表」展示内容

问题描述

我是Django新手,希望按照「分类名称+对应产品列表」的格式展示产品(主分类Main_Category是Product模型的外键),但尝试多种方法后,仅能在页面中显示分类,无法展示对应产品。以下是相关代码:

模型代码(models.py)

from django.utils import timezone
from distutils.command.upload import upload
from email.policy import default
from django.db import models
from django.contrib.auth.models import User

# Create your models here.
class Main_Category(models.Model):
    name=models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Sub_Category(models.Model):
    main_category=models.ForeignKey(Main_Category,on_delete=models.CASCADE)
    name=models.CharField(max_length=100)
    def __str__(self):
        return self.name
    
class Product(models.Model):
    Status=('publish','publish'),('draft','draft')

    product_id=models.AutoField
    name=models.CharField(max_length=50)
    category=models.ForeignKey(Main_Category,on_delete=models.CASCADE,null=True,default="")
    sub_category=models.ForeignKey(Sub_Category,on_delete=models.CASCADE,null=True,default="")
    price=models.IntegerField(default=0)
    des=models.CharField(max_length=2000)
    status=models.CharField(choices=Status,max_length=200)
    delivery=models.IntegerField(null=True)
    date=models.DateTimeField()
    image=models.ImageField(upload_to="shop/images",default="Status")
    slug=models.CharField(max_length=150)
    def __str__(self):
        return self.name
    @property
    def get_products(self):
        return Product.objects.filter(categories__title=self.name)

class Orders(models.Model):
    user=models.ForeignKey(User,on_delete=models.CASCADE)
    amount=models.CharField(max_length=55)
    Order_id=models.AutoField(primary_key=True)
    name=models.CharField(max_length=55)
    email=models.CharField(max_length=30)
    address=models.CharField(max_length=200)
    phone=models.CharField(max_length=15)
    city=models.CharField(max_length=20)
    state=models.CharField(max_length=20)
    zip_code=models.CharField(max_length=10)
    date=models.DateTimeField(default=timezone.now)
    def __str__(self):
        return self.user.username

class OrderItem(models.Model):
    order=models.ForeignKey(Orders,on_delete=models.CASCADE)
    product=models.CharField(max_length=200)
    image=models.ImageField(upload_to="shop/images/cust_image")
    quantity=models.CharField(max_length=20)
    price=models.CharField(max_length=15)
    total=models.CharField(max_length=1000)
    def __str__(self):
        return self.order.user.username

视图代码(views.py)

from django.shortcuts import redirect, render
from .models import Main_Category, Product,Sub_Category,Orders,OrderItem
from django.core.paginator import Paginator
from django.contrib.auth.decorators import login_required
from cart.cart import Cart
from django.contrib.auth.models import User,auth
from django.contrib import messages

def index(request):
    allproduct=Product.objects.all() ###filter(publish)which product you want to display in homepage
    main_category=Main_Category.objects.all().order_by('-id')
    categoryID = request.GET.get('main_category')
    if categoryID:
        allproduct=Product.objects.filter(sub_category=categoryID)
    else:
        allproduct=Product.objects.all()

    paginator=Paginator(allproduct,5)
    page_number=request.GET.get('page')
    pagedata=paginator.get_page(page_number)
    totalpage=pagedata.paginator.num_pages
    print(allproduct)
    context= {'allproduct':allproduct,
              'main_category':main_category,
              'allproduct':pagedata,
              'totalpagelist':[n+1 for n in range(totalpage)]
              
    }

    return render (request,"shop/index.html",context)

HTML模板代码

{% for product in allproduct %}
<div class="col-6 col-sm-6 col-md-6 col-lg-3">
    <div class="card">
        <img class="card-img-top " src='/media/{{product.image}}' alt="Card image cap">
        <div class="card-body">
            <h4 class="card-title">{{product.name}}</h4>
            <p class="card-text">{{product.des |truncatechars:50}}</p>
            <p class="card-text">{{product.time}}</p>
            <div class="row">
                <div class="col">
                    <a class=" btn btn-primary" href="{% url 'cart_add' product.id %}">Add to cart</a>
                    <a  class="btn btn-danger ">{{product.price}} Tk</a>
                </div>
            </div>
        </div>
    </div>        
</div>
{% endfor %}

解决方案

核心问题分析

  1. 视图未按分类组织产品数据,仅传递了独立的分类和产品列表,无法建立关联
  2. Product模型中get_products属性逻辑错误,引用了不存在的字段
  3. 模板仅遍历产品列表,未关联分类展示对应内容
  4. 模型和模板存在多处字段名不匹配、语法错误

分步修正

1. 修复模型错误

  • 修正Product的Status定义(嵌套元组格式错误)
  • 补全product_id的主键定义
  • 删除无用且错误的get_products属性

修改后的Product模型片段:

class Product(models.Model):
    # 修正Status格式
    Status = (('publish', 'publish'), ('draft', 'draft'))
    # 补全主键定义
    product_id = models.AutoField(primary_key=True)
    name=models.CharField(max_length=50)
    category=models.ForeignKey(Main_Category,on_delete=models.CASCADE,null=True,default="")
    # 其他字段保留...

2. 重构视图,按分类关联产品

修改index视图,预加载分类及对应产品,减少数据库查询:

def index(request):
    # 预加载主分类及其关联的产品,避免N+1查询
    main_categories = Main_Category.objects.all().order_by('-id').prefetch_related('product_set')
    
    categoryID = request.GET.get('main_category')
    context = {'main_categories': main_categories}
    
    # 处理分类筛选逻辑(可选)
    if categoryID:
        filtered_products = Product.objects.filter(category=categoryID, status='publish')
        paginator = Paginator(filtered_products, 5)
        page_number = request.GET.get('page')
        pagedata = paginator.get_page(page_number)
        totalpage = pagedata.paginator.num_pages
        context.update({
            'filtered_products': pagedata,
            'totalpagelist': [n+1 for n in range(totalpage)],
            'selected_category': categoryID
        })
    
    return render(request, "shop/index.html", context)

3. 修改模板,实现「分类+产品」展示结构

调整模板,先遍历分类,再展示对应产品:

<!-- 遍历所有主分类,展示分类名及对应产品 -->
{% for category in main_categories %}
<div class="category-block">
    <h2>{{ category.name }}</h2>
    <div class="row">
        {% for product in category.product_set.all %}
            {% if product.status == 'publish' %}
            <div class="col-6 col-sm-6 col-md-6 col-lg-3">
                <div class="card">
                    <img class="card-img-top" src='/media/{{ product.image }}' alt="{{ product.name }}">
                    <div class="card-body">
                        <h4 class="card-title">{{ product.name }}</h4>
                        <p class="card-text">{{ product.des|truncatechars:50 }}</p>
                        <!-- 修正字段名:time改为date -->
                        <p class="card-text">{{ product.date }}</p>
                        <div class="row">
                            <div class="col">
                                <a class="btn btn-primary" href="{% url 'cart_add' product.id %}">Add to cart</a>
                                <a class="btn btn-danger">{{ product.price }} Tk</a>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            {% endif %}
        {% empty %}
            <p>该分类暂无已发布产品</p>
        {% endfor %}
    </div>
</div>
{% endfor %}

<!-- 可选:展示筛选后的分页产品列表 -->
{% if filtered_products %}
<div class="filtered-results">
    <h2>分类筛选结果</h2>
    <div class="row">
        {% for product in filtered_products %}
        <div class="col-6 col-sm-6 col-md-6 col-lg-3">
            <div class="card">
                <img class="card-img-top" src='/media/{{ product.image }}' alt="{{ product.name }}">
                <div class="card-body">
                    <h4 class="card-title">{{ product.name }}</h4>
                    <p class="card-text">{{ product.des|truncatechars:50 }}</p>
                    <p class="card-text">{{ product.date }}</p>
                    <div class="row">
                        <div class="col">
                            <a class="btn btn-primary" href="{% url 'cart_add' product.id %}">Add to cart</a>
                            <a class="btn btn-danger">{{ product.price }} Tk</a>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        {% endfor %}
    </div>
    <!-- 分页导航 -->
    <div class="pagination">
        {% for page in totalpagelist %}
        <a href="?page={{ page }}&main_category={{ selected_category }}">{{ page }}</a>
        {% endfor %}
    </div>
</div>
{% endif %}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 10:50:37