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

如何从Django模型获取下拉选项?订单页面产品选项空白排查

Django订单页面产品下拉选项空白问题排查与修复

问题描述

在Django项目中,订单页面的HTML无法渲染OrderModel关联的产品下拉选项,期望显示ProductModel的model_name字段,但当前下拉选项为空白。相关原代码如下:

原models.py代码

from cgi import print_form
from email.policy import default
from enum import unique
from django.db import models

# Create your models here.
class ProductModel(models.Model):
    product_id = models.CharField(max_length=100,unique=True, default = '0')
    product_name = models.CharField(max_length=100, default=" ")
    model_name = models.CharField(max_length=100, default=" ")

    def __str__(self):
        return str(self.product_id)

productchoice = (ProductModel.objects)
        
class OrderModel(models.Model):
    order_id = models.AutoField(unique=True, primary_key=True)
    Customer_name = models.CharField(max_length=100)
    Father_name = models.CharField(max_length=100)
    Village = models.CharField(max_length=100)
    Tehsil = models.CharField(max_length=100)
    District = models.CharField(max_length=100)
    State = models.CharField(max_length=100)
    product = models.ForeignKey(ProductModel, on_delete = models.CASCADE, default= 0)

    def __str__(self):
        return str(self.order_id)

原views.py代码

from email import message_from_binary_file
from django.shortcuts import render
from .models import OrderModel, ProductModel
from .forms import OrderForm, ProductForm
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib import messages
from django.contrib.messages import get_messages

# Create your views here.
def home(request):
    order_form = OrderForm
    if request.method == 'POST':
        order_form = OrderForm(request.POST)

        if order_form.is_valid():
            order_form.save()
            messages.success(request, ('Your data was successfully added!'))
            return HttpResponseRedirect('/')
        else:
            messages.error(request, order_form.errors)

        
    orders = OrderModel.objects.all()
    
    context = {'order':orders, 'form':order_form}
    return render(request,'Orders/addorder.html',context)

def product(request):
    product_form = ProductForm

    if request.method == 'POST':
        product_form = ProductForm(request.POST)

        if product_form.is_valid():
            product_form.save()
            messages.success(request,"Your Products is successfully saved!")
            return HttpResponseRedirect('/')
        else:
            messages.error(request,product_form.errors)

    products = ProductModel.objects.all()
    context = {'product':products, 'form':product_form}
    return render(request,'Orders/addproduct.html',context)

原HTML模板代码

{% extends 'OMS/index.html' %}
{% load static %}

{% block title %}
    <title>Order</title>
{% endblock %}

{% block main %}
    

    <link rel="stylesheet" href="{% static 'addorder.css' %}">
    <div class="container mp-3">
        <h1>Create your Order</h1>
        
         <form action="" method="POST">
            {% csrf_token %}
            <div>
                <label for="Customer Name" class="form-label">Customer Name: </label>
                {{ form.Customer_name }}
            </div>
            <div>
                <label for="Father Name" class="form-label">Father Name: </label>
                {{ form.Father_name }}
            </div>
            <div>
                <label for="Village" class="form-label">Village: </label>
                {{ form.Village }}
            </div>
            <div>
                <label for="Tehsil" class="form-label">Tehsil: </label>
                {{ form.Tehsil }}
            </div>       
            <div> 
                <label for="District" class="form-label">District: </label>
                {{ form.District }}
            </div>
            <div>
                <label for="State" class="form-label">State: </label>
                {{ form.State }}
            </div>
            <div>
                <select name="product" id="productselection">
                        {% for form in form %}
                            <option value="{{ form.product.product_id }}">{{ form.product.model_name }}</option>
                        {% endfor %}
                </select>
            </div> 

           
            <button type="submit">Submit</button>
            {% if messages %}
                <ul class="messages">
                {% for message in messages %}
                    <li {% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
                {% endfor %}
                </ul>
            {% endif %}
        </form>
    </div>
{% endblock %}

原forms.py代码

from django import forms
from .models import OrderModel, ProductModel, productchoice
 

class OrderForm(forms.ModelForm):
    
    Customer_name = forms.CharField(widget=forms.TextInput(attrs={
        "class":"input"
    }))

    class Meta:
        model = OrderModel
        fields = "__all__"
        

class ProductForm(forms.ModelForm):

    class Meta:
        model = ProductModel
        fields = "__all__"

问题排查

  • 模板渲染逻辑错误:HTML中手动编写的<select>循环的是form对象本身({% for form in form %}),会遍历表单字段而非产品数据,同时变量名冲突导致无法获取产品信息。
  • 上下文未传递产品数据:视图home函数未将ProductModel实例列表传入模板上下文,手动渲染下拉时无数据源。
  • ProductModel的__str__方法不符合需求:当前__str__返回product_id,即使使用Django表单自动生成下拉,显示的也是产品ID而非期望的model_name。
  • 外键默认值存在风险:OrderModel的product字段设置default=0,若数据库中无ID为0的产品,会导致关联错误。

修复方案(推荐使用Django表单自动渲染)

步骤1:修改ProductModel的__str__方法

让__str__返回model_name,表单生成的下拉选项会直接显示产品型号:

# models.py
class ProductModel(models.Model):
    product_id = models.CharField(max_length=100, unique=True, default='0')
    product_name = models.CharField(max_length=100, default=" ")
    model_name = models.CharField(max_length=100, default=" ")

    def __str__(self):
        return self.model_name  # 修改为返回model_name

# 移除无用的productchoice变量
class OrderModel(models.Model):
    order_id = models.AutoField(unique=True, primary_key=True)
    Customer_name = models.CharField(max_length=100)
    Father_name = models.CharField(max_length=100)
    Village = models.CharField(max_length=100)
    Tehsil = models.CharField(max_length=100)
    District = models.CharField(max_length=100)
    State = models.CharField(max_length=100)
    # 允许订单暂时不选产品,设置null=True, blank=True;否则移除default
    product = models.ForeignKey(ProductModel, on_delete=models.CASCADE, null=True, blank=True)

    def __str__(self):
        return str(self.order_id)

步骤2:简化HTML模板,使用表单自动渲染下拉

删除手动编写的<select>代码,直接使用Django表单生成的字段:

{% extends 'OMS/index.html' %}
{% load static %}

{% block title %}
    <title>Order</title>
{% endblock %}

{% block main %}
    <link rel="stylesheet" href="{% static 'addorder.css' %}">
    <div class="container mp-3">
        <h1>Create your Order</h1>
        
        <form action="" method="POST">
            {% csrf_token %}
            <div>
                <label for="Customer Name" class="form-label">Customer Name: </label>
                {{ form.Customer_name }}
            </div>
            <div>
                <label for="Father Name" class="form-label">Father Name: </label>
                {{ form.Father_name }}
            </div>
            <div>
                <label for="Village" class="form-label">Village: </label>
                {{ form.Village }}
            </div>
            <div>
                <label for="Tehsil" class="form-label">Tehsil: </label>
                {{ form.Tehsil }}
            </div>       
            <div> 
                <label for="District" class="form-label">District: </label>
                {{ form.District }}
            </div>
            <div>
                <label for="State" class="form-label">State: </label>
                {{ form.State }}
            </div>
            <!-- 替换手动select为表单字段 -->
            <div>
                <label for="{{ form.product.id_for_label }}" class="form-label">产品型号: </label>
                {{ form.product }}
            </div> 

            <button type="submit">Submit</button>
            {% if messages %}
                <ul class="messages">
                {% for message in messages %}
                    <li {% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
                {% endfor %}
                </ul>
            {% endif %}
        </form>
    </div>
{% endblock %}

步骤3(可选):优化表单字段样式

如果需要给产品下拉添加样式,可在OrderForm中自定义widget:

# forms.py
from django import forms
from .models import OrderModel, ProductModel

class OrderForm(forms.ModelForm):
    Customer_name = forms.CharField(widget=forms.TextInput(attrs={
        "class":"input"
    }))
    # 自定义产品下拉的样式
    product = forms.ModelChoiceField(
        queryset=ProductModel.objects.all(),
        widget=forms.Select(attrs={
            "class": "input"
        })
    )

    class Meta:
        model = OrderModel
        fields = "__all__"

class ProductForm(forms.ModelForm):
    class Meta:
        model = ProductModel
        fields = "__all__"

备选方案:手动渲染下拉(不推荐)

如果一定要手动编写<select>,需修改视图和模板:

修改视图传递产品数据

# views.py
def home(request):
    order_form = OrderForm()  # 实例化表单,原代码是类而非实例
    if request.method == 'POST':
        order_form = OrderForm(request.POST)
        if order_form.is_valid():
            order_form.save()
            messages.success(request, ('Your data was successfully added!'))
            return HttpResponseRedirect('/')
        else:
            messages.error(request, order_form.errors)
        
    orders = OrderModel.objects.all()
    # 添加产品列表到上下文
    products = ProductModel.objects.all()
    context = {'order': orders, 'form': order_form, 'products': products}
    return render(request,'Orders/addorder.html',context)

修改模板循环产品列表

<!-- HTML模板中的select部分 -->
<div>
    <label for="productselection" class="form-label">产品型号: </label>
    <select name="product" id="productselection">
        {% for product in products %}
            <option value="{{ product.id }}">{{ product.model_name }}</option>
        {% endfor %}
    </select>
</div>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 10:20:43