如何在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
相关产品推荐
相关产品推荐

