python - 具有反向 ManytoMany 字段的 ModelForm

标签 python django django-models

我无法让 ModelMultipleChoiceField 显示模型实例的初始值。我无法找到有关该领域的任何文档,而且我一直在阅读的示例太令人困惑了。 Django: ModelMultipleChoiceField doesn't select initial choices看起来很相似,但是那里给出的解决方案对模型实例来说不是动态的。

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

模型.py

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

表单.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),
    )

View .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})

它返回的表单没有选择实例的链接项目(看起来像:Django multi-select widget?)。此外,它不会更新用户在保存表单时所做的任何选择。

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

最佳答案

这里有一个比旧的解决方案更好的解决方案,旧的确实行不通。

您必须在创建表单时从数据库中加载现有的相关值,并在保存表单时将它们保存回来。我在相关名称(经理)上使用 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

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

关于python - 具有反向 ManytoMany 字段的 ModelForm,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7018134/

相关文章:

javascript - Django 中的动态表单有任何现有解决方案吗?

python - Django 模型 : store reference to unknown class

python - 如何在 Django 中获取 ContentType 的类名

python - 使用 pandas 进行代码/循环优化以创建两个矩阵

python - Pandas:如何应用传递的条件运算符来选择 pandas 中的行?

Django 和南 : using south makes syncdb show myapp as 'not synced (use migrations)'

python - 使用 Ajax 验证并提交 Django 表单 (django-crispy-forms)

Mac 上 Eclipse IDE 中的 Python Kivy

python - 让 OneHotEncoder 管理转换步骤中看不见的值

python - Django 中的元素计数