Replacing ManyToMany-Relation with ModelChoiceField

别来无恙 提交于 2019-12-24 14:24:00

问题


I'm stuck trying to render a ManyToMany-Relation as a ModelChoiceField instead of a ModelMultipleChoiceField. So I tried the following (simplified):

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']

The form renders correctly and I can select a registered user from the list. But after submitting the form, I'll get a TypeError with the message 'User' object is not iterable. I think that the save() function needs two values to save a ManyToMany-Relation but the ModelChoiceField returns only one. I don't know how to solve that...


回答1:


You can deal with this by changing the widget:

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 and Django renders this appropriately:

ModelChoiceField

class ModelChoiceField(**kwargs)

Default widget: Select

Alternatively you can use SelectMultiple and CheckboxSelectMultiple.




回答2:


After fiddling around I got an working solution. Wtowers proposal is not working. Why? Read that one: https://stackoverflow.com/a/13336492/2153744

So we have to handle everything on our own.

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


来源:https://stackoverflow.com/questions/30303947/replacing-manytomany-relation-with-modelchoicefield

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!