用 ModelChoiceField 替换多对多关系
Replacing ManyToMany-Relation with ModelChoiceField
我无法尝试将多对多关系呈现为 ModelChoiceField 而不是 ModelMultipleChoiceField。所以我尝试了以下(简化):
models.py:
class Project(models.Model):
name = models.CharField(max_length=20, unique=True)
manager = models.ManyToManyField(User, related_name="manager_related")
forms.py:
class ProjectForm(forms.ModelForm):
manager = forms.ModelChoiceField(queryset=User.objects.all(),
empty_label='Choose Manager', required=False)
class Meta:
model = Project
fields = ['name', 'manager']
表单正确呈现,我可以 select 列表中的注册用户。但是在提交表单后,我会收到 TypeError
消息 'User' object is not iterable
。我认为 save() 函数需要两个值来保存多对多关系,但 ModelChoiceField returns 只需要一个。我不知道如何解决...
您可以通过更改小部件来处理此问题:
forms.py:
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = ['name', 'manager']
widgets = {
'manager': forms.Select(),
}
Select widget is the default widget for ModelChoiceField
并且 Django 适当地呈现它:
class ModelChoiceField(**kwargs)
Default widget: Select
或者您可以使用 SelectMultiple
and CheckboxSelectMultiple
。
经过一番摸索,我得到了一个可行的解决方案。 Wtowers 提案无效。为什么?阅读那个:
所以我们必须自己处理所有事情。
forms.py
# helper class: returning full_name instead of username
class UserModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return obj.get_full_name()
class ProjectForm(forms.ModelForm):
manager = UserModelChoiceField(queryset=User.objects.all(), label='Manager', required=True)
class Meta:
model = Project
fields = ['name']
views.py
if request.method == 'POST':
form = ProjectForm(request.POST)
if form.is_valid():
# get cleaned data from form
prj_name = form.cleaned_data['name']
prj_manager = form.cleaned_data['manager'] # this is a User-object
# generate project and store it to db
prj = Project(name=prj_name)
prj.save()
# handling now m2m relation for manager
prj.manager.add(prj_manager)
return HttpResponseRedirect("/project/list")
else:
form = ProjectForm()
我无法尝试将多对多关系呈现为 ModelChoiceField 而不是 ModelMultipleChoiceField。所以我尝试了以下(简化):
models.py:
class Project(models.Model):
name = models.CharField(max_length=20, unique=True)
manager = models.ManyToManyField(User, related_name="manager_related")
forms.py:
class ProjectForm(forms.ModelForm):
manager = forms.ModelChoiceField(queryset=User.objects.all(),
empty_label='Choose Manager', required=False)
class Meta:
model = Project
fields = ['name', 'manager']
表单正确呈现,我可以 select 列表中的注册用户。但是在提交表单后,我会收到 TypeError
消息 'User' object is not iterable
。我认为 save() 函数需要两个值来保存多对多关系,但 ModelChoiceField returns 只需要一个。我不知道如何解决...
您可以通过更改小部件来处理此问题:
forms.py:
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = ['name', 'manager']
widgets = {
'manager': forms.Select(),
}
Select widget is the default widget for ModelChoiceField
并且 Django 适当地呈现它:
class ModelChoiceField(**kwargs)
Default widget: Select
或者您可以使用 SelectMultiple
and CheckboxSelectMultiple
。
经过一番摸索,我得到了一个可行的解决方案。 Wtowers 提案无效。为什么?阅读那个:
所以我们必须自己处理所有事情。
forms.py
# helper class: returning full_name instead of username
class UserModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return obj.get_full_name()
class ProjectForm(forms.ModelForm):
manager = UserModelChoiceField(queryset=User.objects.all(), label='Manager', required=True)
class Meta:
model = Project
fields = ['name']
views.py
if request.method == 'POST':
form = ProjectForm(request.POST)
if form.is_valid():
# get cleaned data from form
prj_name = form.cleaned_data['name']
prj_manager = form.cleaned_data['manager'] # this is a User-object
# generate project and store it to db
prj = Project(name=prj_name)
prj.save()
# handling now m2m relation for manager
prj.manager.add(prj_manager)
return HttpResponseRedirect("/project/list")
else:
form = ProjectForm()