使用 Django 中的 ManyToManyField 的特定参数在表单中自定义查询

Customize query in forms with specific arguments for ManyToManyField in Django

我有一个名为 projects 的应用程序。其中一个字段是 contributors,其中用户列表存储在 ManyToManyField 中。我试图使在列表中添加和删除用户成为可能。使用 ModelChoiceField 添加所有用户的已传递查询集非常容易。从列表中删除用户仍然让我望而却步。我想了解的是如何以及在何处传递附加参数,以便我可以处理表单中的查询,因此它将仅列出来自特定项目的用户。

添加用户

models.py

# Model for projects
class Project(models.Model):
    ...
    contributors = models.ManyToManyField(User, blank=True)
    ...

forms.py

class AddUserForm(forms.Form):
    user = forms.ModelChoiceField(queryset=User.objects.all())

    class Meta:
        model = Project
        fields = [
            "user",
        ]

views.py

# Add task to a project
@login_required()
def projects_adduser(request, id):

    # Fetch the project if it exists
    project = get_object_or_404(Project, id=id)

    # Form for adding users to contributors list
    form = AddUserForm(request.POST or None)

    # Validate the form
    if form.is_valid():
        user = form.cleaned_data.get("user")
        project.contributors.add(user)
        project.save()
        messages.success(request, "User successfully added to project!")
        return HttpResponseRedirect(project.get_edit_url())

    # Context dict to return for template
    context = {
        "title": "Add user to project: " + project.title,
        "form": form,
        "instance": project,
    }
    return render(request, template + '/form.html', context)

我决定从这个周末开始帮助在 Whosebug 中使用 Django 的人。我通常在这里发布问题。我想是时候给人们一个答案了。这是我的开始!激动人心!我使用 Django WebFramework 不到 2 个月。所以我的回答可能还不够,或者还有其他更好的方法。但我想出这种方法来解决你的问题。 (甚至我亲自用笔记本电脑测试自己写代码!)

我的示例代码在这里

models.py

from django.db import models
from django.contrib.auth.models import User

# Create your models here.
class Project(models.Model):
    contributors = models.ManyToManyField(User, blank=True)

views.py

from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect
from barrierfree.models import Project
from barrierfree.forms import AddUserForm

# Create your views here.
def projects_adduser(request, id):

    # Fetch the project if it exists
    project = get_object_or_404(Project, pk=id)
    pk_number_project = project.pk
    # Form for adding users to contributors list
    form = AddUserForm(request.POST, project=pk_number_project)

    # Validate the form
    if form.is_valid():
        user = form.cleaned_data.get("user")
        print ("validated!")
        return HttpResponseRedirect('/Sucess')    
    # Context dict to return for template

    return render(request, 'test.html', {'form':form})

urls.py

from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^test/$', views.projects_adduser, {'id':1}, name='test'),
]

test.html

<form action="." method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="OK">
</form>

forms.py

from django import forms
from django.contrib.auth.models import User
from barrierfree.models import Project

class AddUserForm(forms.Form):
    user = forms.ModelChoiceField(queryset=None)

    class Meta:
        model = Project
        fields = [
            "user",
        ]

    def __init__(self, *args, **kwargs):
        pk_num_project = kwargs.pop('project', None)
        print (pk_num_project)
        super(AddUserForm, self).__init__(*args, **kwargs)
        self.fields['user'].queryset = User.objects.all().filter(project__pk=pk_num_project)

这里是如何操作的解释。

当我阅读你的代码时,你似乎通过视图的参数传递了特定项目的 pk 号。因为你写了def projects_adduser(request, id):。所以我在 url 中给了 pk=1 来进行这样的测试 url(r'^test/$', views.projects_adduser, {'id':1}, name='test') 然后你将在启动表单实例时传递与 pk 编号匹配的项目实例。 form = AddUserForm(request.POST, project=pk_number_project) 那么您将只显示此项目中的用户。

def __init__(self, *args, **kwargs):
        pk_num_project = kwargs.pop('project', None)
        print (pk_num_project)
        super(AddUserForm, self).__init__(*args, **kwargs)
        self.fields['user'].queryset = User.objects.all().filter(project__pk=pk_num_project)

然后通过覆盖 init 方法初始化要在表单中显示的数据。

queryset = User.objects.all().filter(project__pk=pk_num_project)

你可以这样过滤,因为 User 和 Project 是 N:N 关系。

希望我能正确理解你的问题并给你正确的答案:)祝你在 Django 的旅途中好运!和平!

您可以将初始用户查询集传递给这样的表单:

form = AddUserForm()
form.fields["user"].queryset = User.objects.filter(project=project)

此外,您不需要调用 project.save()project.contributors.add(user) 已经在执行查询以添加 m2m 连接