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

