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

如何在Django中实现商品注册时的下拉菜单分类选择功能

Django实现分类下拉选择功能解决方案

你的需求是让用户提交商品时从数据库已有的分类中下拉选择,现有代码的核心问题是字段不匹配、分类选项写死、模板渲染逻辑错误,按以下步骤修改即可实现:


1. 表单层修改(两种方案可选)

方案1:推荐:使用ModelForm+ModelChoiceField(无需手动维护分类选项)

ModelChoiceField是Django专门针对外键字段设计的表单字段,会自动从关联表拉取数据渲染为下拉框,数据库新增/删除分类时自动同步,无需修改代码:

# forms.py 完整代码
from django import forms
from .models import Product, Category

class ProductForm(forms.ModelForm):
    category_code = forms.ModelChoiceField(
        queryset=Category.objects.all(),
        label="카테고리",
        empty_label="请选择分类",
        error_messages={'required': "请选择商品分类"},
        widget=forms.Select(attrs={'class': 'form-control'})
    )
    
    class Meta:
        model = Product
        fields = ['name', 'benefit', 'detail', 'target_price', 'start_date', 'due_date', 'image', 'category_code']
        labels = {
            'name': '상품명',
            'benefit': '공동구매 취지',
            'detail': '상품 설명',
            'target_price': '목표금액',
            'start_date': '모집 시작일',
            'due_date': '모집 마감일',
            'image': '상품 이미지'
        }
        error_messages = {
            'name': {'required': '상품명을 입력하세요.'},
            'benefit': {'required': '공동구매 취지를 입력해주세요.'},
            'detail': {'required': '상품 설명을 입력하세요'},
            'target_price': {'required': '목표 금액을 입력하세요.'},
            'start_date': {'required': '모집 시작일을 선택해주세요.'},
            'due_date': {'required': '모집 마감일을 선택해주세요.'},
            'image': {'required': '사진을 첨부해주세요.'}
        }
        widgets = {
            'benefit': forms.Textarea(attrs={'class': 'form-control', 'rows': 5}),
            'detail': forms.Textarea(attrs={'class': 'form-control', 'rows': 10}),
            'start_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
            'due_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
        }

方案2:普通Form动态加载分类选项

如果不想用ModelForm,可在表单初始化时动态从数据库拉取分类生成选项:

# forms.py 核心修改部分
class ProductForm(forms.Form):
    # 其他字段保持不变,把原来的category字段替换为下面的category_code
    category_code = forms.ChoiceField(
        label="카테고리",
        error_messages={'required': "请选择商品分类"},
        widget=forms.Select(attrs={'class': 'form-control'})
    )

    # 初始化时动态加载分类选项
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['category_code'].choices = [(cat.category_code, cat.name) for cat in Category.objects.all()]

2. 视图层修改

修复原代码中slug赋值错误的问题,使用ModelForm的话无需手动逐个字段赋值:

# views.py 完整代码
from django.shortcuts import render, redirect
from django.utils.text import slugify
from zeronine.models import Category
from .forms import ProductForm

def product_upload(request):
    current_category = None
    categories = Category.objects.all()

    if request.method == "POST":
        form = ProductForm(request.POST, request.FILES)
        if form.is_valid():
            product = form.save(commit=False)
            # 关联当前登录用户,生成slug
            product.username = request.user
            product.slug = slugify(product.name, allow_unicode=True)
            product.save()
            # 提交成功后重定向到列表页,避免重复提交
            return redirect('zeronine:product_list') # 替换为你实际的商品列表路由名
    else:
        form = ProductForm()

    return render(request, 'product/product_upload.html', {
        'form': form, 
        'current_category': current_category, 
        'categories': categories
    })

3. 模板层修改

原模板强制将非详情字段渲染为input标签,导致下拉框无法正常显示,直接渲染表单字段即可:

{% extends "base.html" %}
{% block content %}
<div class="container my-4">
    <h3 style="margin-top:40px; margin-bottom: 15px; text-align: center"><b>상품 등록</b></h3>
    <div class="row mt-5">
        <div class="col-12">
            <form method="POST" action="{% url 'zeronine:product_upload' %}" enctype="multipart/form-data">
                {% csrf_token %}
                {% for field in form %}
                    <div class="mb-3">
                        <label for="{{ field.id_for_label }}" class="form-label"><b>{{ field.label }}</b></label>
                        {{ field }}
                        {% if field.errors %}
                            <div class="text-danger mt-1">{{ field.errors }}</div>
                        {% endif %}
                    </div>
                {% endfor %}
                <button type="submit" class="btn btn-primary" style="float: right; background: #637B46; border: white">등록하기</button>
            </form>
        </div>
    </div>
</div>
{% endblock %}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 01:06:03