Django在一个formset上的多对多限制选择,所以强制删除不活动?

时间:2017-10-31 13:58:08

标签: django formset inline-formset

要求是many-to-manyusers之间的projects关系。

UserProject模型都有is_active属性。

使用更新视图修改UserProject时,有一个内联formset。

many-to-many字段通过中间表控制。

User型号上:

projects = models.ManyToManyField(
        Project,
        through=ProjectMembership
    )

Project型号上:

users = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        through='ProjectMembership'
    )

ProjectMembership中间模型上,我正在设置limit_choices_to

user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.PROTECT,
        limit_choices_to={'is_active': True},
)
project = models.ForeignKey(
    Project,
    on_delete=models.PROTECT,
    limit_choices_to={'is_active': True},
)

在表单集上,用户只能分配给新项目,反之亦然。 问题在于现有项目处于非活动状态。

因此,您可以将活动项目保存到用户:

Save active projects to a project

但是当您将is_active的{​​{1}}状态更改为Stackoverflow Answering时:

The option does not exists

然后当您尝试保存时,强制您删除该行:

Forced deleting of formset row inactive

理想情况下,我希望False项目为inactive或根本不可见。

这意味着会覆盖disabledget_initial_data。 他们也不会使用initial queryset方法进行验证。我该如何具体解决这个问题?

clean

Formset

class ProjectMembershipForm(forms.ModelForm): class Meta: model = ProjectMembership fields = ( 'user', 'project', 'is_project_manager', ) ProjectMembershipFormSet = forms.inlineformset_factory( Project, ProjectMembership, form=ProjectMembershipForm, extra=1, can_delete=True )

UserUpdateView

1 个答案:

答案 0 :(得分:0)

你是如何做你的表格的?基于类的视图?更新视图? FormView控件?如果您发布您的观看代码,我将能够提供更好的答案。

如果您使用任何形式的视图,解决方案应该非常简单。您只需要将所需的查询集作为参数传递给表单域。

class AddProjectToUserForm(forms.form):
    projects = forms.ModelChoiceField(queryset=Partner.objects.filter(is_active=True))

编辑:对于modelForm,请尝试以下方法:

class ProjectMembershipForm(forms.ModelForm):
    class Meta:
        model = ProjectMembership
        fields = (
            'user',
            'project',
            'is_project_manager',
        )

    def __init__(self, *args, **kwargs):
        super(ProjectMembershipForm, self).__init__(*args, **kwargs)
        self.fields['project'].queryset = Project.objects.filter(is_active=True)
        self.fields['user'].queryset = User.objects.filter(is_active=True)

self.fields保存对表单上所有字段的引用,并允许您在将它们发送到浏览器之前覆盖disabled之类的属性。如果您想了解更多相关信息,请将import ipdb; ipdb.set_trace()放入init方法并在self.fields内闲逛。

我希望有所帮助。

编辑二: 在这种情况下,您应该尝试对 init 中的字段进行其他修改。如果“初始”数据是非法的,将该字段设置为禁用该怎么办?

def __init__(self, *args, **kwargs):
    super(ProjectMembershipForm, self).__init__(*args, **kwargs)
    project = self.fields['project']
    if projcet.initial and project.initial not in project.queryset:
        project.disabled = True

我不肯定会有效,但类似的事情应该可以解决问题。