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

如何在Django的BuildOrderForm下拉菜单中仅显示当前培训选项?

问题描述

我开发了一个允许用户注册课程(基于TrainingInstance模型)的应用,这些课程在Training模型中被标记为「current(当前)」或「past(过去)」类别。当在模板中展示BuildOrderForm表单时,希望下拉菜单仅显示属于当前培训的选项。请问如何在不使用JavaScript或Ajax的情况下,在Django中实现该需求?


原代码

forms.py

class BuildOrderForm(forms.ModelForm):
    class Meta:
        model = Order
        fields = ['training_registered']

models.py

class Training(models.Model):
    """ Model which specifies the training category (name) and whether they are Past or Present""" 
    YEAR = (
        ('current', 'current'),
        ('past', 'past'),
        )
    name = models.CharField(max_length=200, null=True)
    year= models.CharField(max_length=200, null=True, choices=YEAR, default='current')
    def __str__(self):
        return self.name

class TrainingInstance(models.Model):
    """ Creates a model of different instances of each training ( May 2021 etc) """ 

    name = models.CharField(max_length=200, null=True, blank=True)
    venue = models.CharField(max_length=200, null=True, blank=True)
    training = models.ForeignKey(Training, on_delete= models.CASCADE, null = True)
    
    training_month = models.CharField(max_length=200, null=True, blank=True)
    participant_date = models.CharField(max_length=20, null=True, blank=True)
    staff_date = models.CharField(max_length=20, null=True, blank=True)
    graduation_date = models.CharField(max_length=200, null=True, blank=True)
    
    def __str__(self):
        return self.name
    
class Order(models.Model):
    REGSTATUS = (
        ('registered', 'registered'),
        ('enrolled', 'enrolled'),
        ('holding', 'holding'),
        ('withdrawn', 'withdrawn'),
        ('waiting', 'waiting'),
        )

    customer = models.ForeignKey(Customer, on_delete= models.CASCADE, null = True)
    training_registered = models.ForeignKey(TrainingInstance, on_delete= models.SET_NULL, blank = True, null = True)
    registration_date = models.DateTimeField(null=True,blank=True)

    regstatus = models.CharField(max_length=200, null=True, choices=REGSTATUS, default='registered')

    def __str__(self):
        return self.customer.username

解决方案

方法1:重写表单的__init__方法

在表单初始化时动态过滤training_registered字段的查询集,只保留关联「当前培训」的课程实例:

class BuildOrderForm(forms.ModelForm):
    class Meta:
        model = Order
        fields = ['training_registered']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 利用ORM跨模型过滤,只保留关联year为current的TrainingInstance
        self.fields['training_registered'].queryset = TrainingInstance.objects.filter(
            training__year='current'
        )

方法2:显式定义字段并指定查询集

直接声明training_registered字段,同时设置过滤后的查询集,适合需要自定义字段属性(如标签、必填性)的场景:

class BuildOrderForm(forms.ModelForm):
    training_registered = forms.ModelChoiceField(
        queryset=TrainingInstance.objects.filter(training__year='current'),
        required=True,  # 根据业务需求调整是否必填
        label='注册课程'
    )

    class Meta:
        model = Order
        fields = ['training_registered']

关键说明

  • 两种方案均通过Django ORM的跨模型关联查询(双下划线training__year表示关联到Training模型的year字段)在后端完成数据筛选,完全不需要前端JS/Ajax参与。
  • 如果需要保留空选项(允许用户不选择课程),可将required设为False,Django默认会添加空选项;也可通过empty_label参数自定义空选项文本,例如empty_label='请选择课程'。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 21:45:33