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



我有一个叫做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)

您可以像这样将初始用户的queryset传递给表单:

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

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

我决定从这个周末开始帮助那些在stackoverflow中使用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):。所以我给了pk=1在url测试像这个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的旅程好运!和平!

相关内容

  • 没有找到相关文章

最新更新