具有反向ManytoMany字段的ModelForm

Edd*_*Edd 6 python django django-models

我无法让ModelMultipleChoiceField显示模型实例的初始值.我一直无法找到有关该领域的任何文档,我一直在阅读的例子太令人困惑了. Django:ModelMultipleChoiceField没有选择初始选择似乎是相似的,但是那里给出的解决方案对模型实例来说不是动态的.

这是我的情况(每个数据库用户连接到一个或多个项目):

models.py

from django.contrib.auth.models import User
class Project(Model):
    users = ManyToManyField(User, related_name='projects', blank=True)
Run Code Online (Sandbox Code Playgroud)

forms.py

from django.contrib.admin.widgets import FilteredSelectMultiple
class AssignProjectForm(ModelForm):
    class Meta:
        model = User
        fields = ('projects',)

    projects = ModelMultipleChoiceField(
        queryset=Project.objects.all(),
        required=False,
        widget=FilteredSelectMultiple('projects', False),
    )
Run Code Online (Sandbox Code Playgroud)

views.py

def assign(request):
    if request.method == 'POST':
        form = AssignProjectForm(request.POST, instance=request.user)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect('/index/')
    else:
        form = AssignProjectForm(instance=request.user)

    return render_to_response('assign.html', {'form': form})
Run Code Online (Sandbox Code Playgroud)

它返回的表单不是选择实例的链接项目(它看起来像:Django多选小部件?).此外,它不会使用保存表单时所做的任何选择来更新用户.

编辑:使用此方法管理解决此问题:http://code-blasphemies.blogspot.com/2009/04/dynamically-created-modelmultiplechoice.html

lit*_*die 8

这是一个比旧的解决方案更好的解决方案,它确实不起作用。

您必须在创建表单时从数据库加载现有的相关值,并在保存表单时将它们保存回来。我使用set()相关名称(经理)的方法为您完成所有工作:删除不再选择的现有关系,并添加已选择的新关系。所以你不必做任何循环或检查。

class AssignProjectForm(ModelForm):

    def __init__(self, *args, **kwargs):
        super(AssignProjectForm, self).__init__(*args, **kwargs)

        # Here we fetch your currently related projects into the field,     
        # so that they will display in the form.
        self.fields['projects'].initial = self.instance.projects.all(
            ).values_list('id', flat=True)

    def save(self, *args, **kwargs):
        instance = super(AssignProjectForm, self).save(*args, **kwargs)

        # Here we save the modified project selection back into the database
        instance.projects.set(self.cleaned_data['projects'])

        return instance
Run Code Online (Sandbox Code Playgroud)

除了简单之外,set()如果您post_save在 m2m 关系上使用 Django 信号(例如等),使用该方法还有另一个优势:如果您在循环中一次添加和删除条目,您将获得每个条目的信号目的。但是,如果您在使用 的一个操作中执行此操作set(),您将只获得一个带有对象列表的信号。如果您的信号处理程序中的代码做了重要的工作,这将是一件大事。


Yuj*_*ita 7

ModelForm's 不会自动用于反向关系。

什么也没有发生,save()因为 aModelForm只知道如何处理自己的字段 -projects不是User模型上的字段,它只是表单上的字段。

您必须告诉您的表单如何使用您的这个新字段来保存自己。

def save(self, *args, **kwargs):
    for project in self.cleaned_data.get('projects'):
        project.users.add(self.instance)
    return super(AssignProjectForm, self).save(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

  • 这就是它没有使用反向关系中的值正确初始化的原因吗?有没有办法让它正确初始化? (3认同)