Django:ModelForm 使用自定义查询预填充复选框

Posted

技术标签:

【中文标题】Django:ModelForm 使用自定义查询预填充复选框【英文标题】:Django : ModelForm Pre-populate Checkbox with Custom Query 【发布时间】:2015-09-06 12:13:24 【问题描述】:

我正在开发我的第一个 Django 项目。

我在两个模型之间存在多对多关系:用户和项目。 在更新项目时,我想显示带有添加新成员的表单,并根据当前项目用户使用正确的选项删除现有成员字段。

这是我目前尝试过的:

    从 URL 获取当前项目 将当前项目传递给模型表单 在表单中,运行自定义查询集。

问题:查询集结果不显示。

在views.py中

类 UpdateProject(LogInRequiredMixin, UpdateView):

""" Class to Edit Project.
"""

form_class = ProjectUpdateForm
template_name = 'project/create.html'

def get_object(self):
    self.project_instance = models.Project.objects.get(pk=self.kwargs['project'])
        return self.project_instance

def get_form_kwargs(self):
    kwargs = super(UpdateProject, self).get_form_kwargs()
    kwargs.update('project': self.project_instance)
    return kwargs

对于表格 项目更新表单

class ProjectUpdateForm(forms.ModelForm):
    """ Form to update Project Field. """

    add_member = forms.CharField(label="Add New Members", widget=forms.CheckboxSelectMultiple)
    del_member = forms.CharField(label="Remove Members", widget=forms.CheckboxSelectMultiple)

    def __init__(self, *args, **kwargs):
        self.project = kwargs.pop('project')
        super(ProjectUpdateForm, self).__init__(*args, **kwargs)
        print MyUser.objects.exclude(pk__in=self.project.members.all())
        print MyUser.objects.filter(pk__in=self.project.members.all())

        self.fields['add_member'].queryset = MyUser.objects.exclude(pk__in=self.project.members.all())
        self.fields['del_member'].queryset = MyUser.objects.filter(pk__in=self.project.members.all())

   # Rest of Class Logic

打印语句正在运行并返回正确的结果,但是我无法在 app.xml 中查看结果。它显示为空白。

另外,我想知道他们实现相同的更简单方法吗? (在我看来,我不应该明确地通过项目?)

【问题讨论】:

两种表单的元类是什么? @Pcriulan For Form class Meta: model = Project fields = ['title', 'description'] 对于 View,我没有使用 Meta 好的,所以您需要在字段中添加自定义字段:fields = ['title', 'description', 'add_member', 'del_member']。这样你就告诉 django 要注意这些字段。 做到了。仍然没有改善。 @Pcriulan 明确地说,它是(并且曾经)在页面上显示两个字段名称,但没有显示任何选项 【参考方案1】:

据我所知,这解决了问题

在模型表单中显式添加多对多字段时,并且您期望多重响应,使用的模块应为ModelMultipleChoiceField

另外,由于我们重写了 init 方法,并且在其中有一个查询集,因此定义它的最佳位置是 init。

最终形式代码:

class ProjectUpdateForm(forms.ModelForm):
    """ Form to update Project Field. """


    def __init__(self, *args, **kwargs):
        self.project = kwargs.pop('project')
        super(ProjectUpdateForm, self).__init__(*args, **kwargs)

        self.fields['add_member'] = forms.ModelMultipleChoiceField(label="Add New members",
                                                                   widget=forms.CheckboxSelectMultiple,
                                                                   queryset=MyUser.objects.exclude(pk__in=self.project.members.all()))
        self.fields['del_member'] = forms.ModelMultipleChoiceField(label="Remove Members",
                                                                   widget=forms.CheckboxSelectMultiple,
                                                                   queryset=MyUser.objects.filter(pk__in=self.project.members.all()))

    class Meta:
        model = Project
        fields = ['title', 'description']

   #Rest of Form Logic

应该这样做!


可能对某人有用

如果我们已经在模型中定义了字段,我们不需要在 init 中完全覆盖它(如果查询需要传递参数)

我们可以在 init 中定义它的查询集 self.fields['field_name'].queryset = 逻辑

并在 Meta 类中添加小部件。


PS:我仍在寻找更简单的方法来访问当前对象,而不是通过 View 显式传递!

【讨论】:

【参考方案2】:

我理解添加add_memberdel_member 操作的想法。

但是为什么你不能只使用一个ModelMultipleChoiceField 来显示可能在项目中的每个用户,并且只使用复选框来显示已经参与项目的用户?

我没有对此进行测试,但它可能看起来像:

class ProjectForm(forms.ModelForm):

    class Meta:
        model = Project
        fields = ['title', 'description']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        current_members = self.instance.members.all() # What are the current members?
        possible_members = User.objects.all() # Change this if you want a different set of users to add.
        self.fields['members'] = forms.ModelMultipleChoiceField(label="Members",
                                                                widget=forms.CheckboxSelectMultiple,
                                                                queryset=possible_members,
                                                                initial=current_members,
                                                                required=False) # If it can be empty

    def save(self, commit=True):
        instance = super().save(commit=False)  # Saving with commit=False add a save_m2m method to self
        if commit:
            instance.members.clear()           # We delete every member
            for m in self.cleaned_data.get('members'): # We them add again every checked user as member at form submission
                instance.members.add(m)
            instance.save()                    # We save the instance
            self.save_m2m()                    # We also save the changes in the M2M relationship.
            return instance

诀窍是检索当前是项目实例成员的用户并预先选中复选框以在所有用户的整个列表中显示他们(选中:是成员的用户,未选中:不是成员的用户)。

因此,如果您选中一个框,则添加用户,如果取消选中,则将其从成员列表中删除。

【讨论】:

【参考方案3】:

首页HTML代码:

<td><input type="checkbox" name="checks[]" value=" customer.pk "></td>

后端views.py代码:

models.Customer.objects.filter(pk__in=request.POST.getlist('checks[]')).update(consultant_id=None)

infact name='V'==getlist('V') ,不需要 []

===========

<td><input type="checkbox" name="checks" value=" customer.pk "></td>

models.Customer.objects.filter(pk__in=request.POST.getlist(''checks'))

【讨论】:

name='arg' getlist('arg')

以上是关于Django:ModelForm 使用自定义查询预填充复选框的主要内容,如果未能解决你的问题,请参考以下文章

Django:ModelForm 自定义错误消息和占位符

django Modelform表单自定义控件

Django-profiles 自定义创建/编辑 modelForm 未正确保存

Django的forms.ModelForm自定义特殊条件认证。

Django之ModelForm组件

Django之ModelForm组件