用ModelChoiceField替换ManyToMany-Relation

时间:2015-05-18 13:01:31

标签: python django django-models django-forms

我试图将ManyToMany-Relation呈现为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']

表单呈现正确,我可以从列表中选择注册用户。但在提交表单后,我会收到TypeError消息'User' object is not iterable。我认为save()函数需要两个值来保存ManyToMany-Relation,但ModelChoiceField只返回一个。我不知道如何解决......

2 个答案:

答案 0 :(得分:1)

您可以通过更改小部件来解决此问题:

forms.py:

class ProjectForm(forms.ModelForm):
    class Meta:
        model = Project
        fields = ['name', 'manager']
        widgets = {
            'manager': forms.Select(),
        }

Select小部件是ModelChoiceField的默认小部件,Django适当地呈现了这个小部件:

  

ModelChoiceField

     

class ModelChoiceField(** kwargs)

     

默认小部件:Select

或者,您可以使用SelectMultipleCheckboxSelectMultiple

答案 1 :(得分:0)

在摆弄后我得到了一个有效的解决方案。 Wtowers提案不起作用。为什么?阅读那个:https://stackoverflow.com/a/13336492/2153744

所以我们必须自己处理所有事情。

<强> 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()