在 Django 的 ModelForm 中,当存在多对多字段时,需要对该字段进行筛选,以便在表单中仅显示特定条件下的选项。例如,在一个项目中,存在两个模型:IdealBehaviour 和 StandardWork,其中 IdealBehaviour 模型包含 cbs 外键字段,指向 CBS 模型,而 StandardWork 模型包含 ideal_behaviour 多对多字段,指向 IdealBehaviour 模型。在使用 TodoListForm 表单来管理 StandardWork 模型时,需要筛选 ideal_behaviour 多对多字段,以便仅显示与当前正在编辑的 CBS 相关联的 IdealBehaviour 选项。
解决方案
为了解决此问题,需要在 TodoListForm 表单的 __init__ 方法中添加代码,以根据当前正在编辑的 StandardWork 实例来筛选 ideal_behaviour 多对多字段。具体代码如下:
class TodoListForm(forms.ModelForm):
class Meta:
model = StandardWork
exclude = ('cbs_and_role', 'publish', 'standard_work_number')
widgets = {
'system_description': forms.Textarea(attrs={'rows': 3}),
}
def __init__(self, *args, **kwargs):
super(TodoListForm, self).__init__(*args, **kwargs)
if self.instance:
self.fields['ideal_behaviour'].queryset = IdealBehaviour.objects.filter(cbs__exact=self.instance.cbs.id)
在上面的代码中,首先定义了一个 TodoListForm 类,继承自 forms.ModelForm。然后在 __init__ 方法中,首先检查是否存在当前正在编辑的 StandardWork 实例,如果存在,则根据该实例的 cbs 外键字段,来筛选 ideal_behaviour 多对多字段。
代码示例
下面是一个完整的代码示例,展示了如何使用 TodoListForm 表单来管理 StandardWork 模型:
from django import forms
from django.db import models
# 定义 IdealBehaviour 模型
class IdealBehaviour(models.Model):
cbs = models.ForeignKey('CBS', null=True, blank=True)
ideal_behaviour = models.CharField(max_length=500, null=True, blank=True)
Description = models.CharField(max_length=1000, null=True, blank=True)
created_time = models.DateTimeField(auto_now_add=True, null=True, blank=True)
# 定义 StandardWork 模型
class StandardWork(models.Model):
cbs_and_role = models.ManyToManyField('CbsRole', null=True, blank=True)
standard_work_number = models.BigIntegerField(null=True, blank=True)
system_name = models.CharField(max_length=500, null=True, blank=True)
system_description = models.TextField(null=True, blank=True)
ideal_behaviour = models.ManyToManyField('IdealBehaviour', null=True, blank=True)
publish = models.BooleanField(default=False)
created_time = models.DateTimeField(auto_now_add=True, null=True, blank=True)
# 定义 TodoListForm 表单
class TodoListForm(forms.ModelForm):
class Meta:
model = StandardWork
exclude = ('cbs_and_role', 'publish', 'standard_work_number')
widgets = {
'system_description': forms.Textarea(attrs={'rows': 3}),
}
def __init__(self, *args, **kwargs):
super(TodoListForm, self).__init__(*args, **kwargs)
if self.instance:
self.fields['ideal_behaviour'].queryset = IdealBehaviour.objects.filter(cbs__exact=self.instance.cbs.id)
# 在视图中使用 TodoListForm 表单
def manage_view(request, pk):
standard_work = StandardWork.objects.get(pk=pk)
form = TodoListForm(instance=standard_work)
if request.method == 'POST':
form = TodoListForm(request.POST, instance=standard_work)
if form.is_valid():
form.save()
return redirect('success_url')
context = {
'form': form,
}
return render(request, 'manage.html', context)
在上面的代码中,首先定义了 IdealBehaviour 和 StandardWork 模型。然后定义了 TodoListForm 表单类,并在 __init__ 方法中添加了 ideal_behaviour 多对多字段的筛选代码。最后在 manage_view 视图中,获取了当前正在编辑的 StandardWork 实例,并将其作为参数传递给 TodoListForm 表单,以便在表单中显示与该实例相关联的 IdealBehaviour 选项。