2016-10-22 52 views
1

我有一個名爲projects的應用程序。其中一個字段爲contributors,其中用戶列表以ManyToManyField存儲。我試圖使用戶可以在列表中添加和刪除用戶。使用ModelChoiceField與所有用戶的傳遞查詢集一起添加已相當簡單。從列表中刪除用戶仍然沒有。我想了解的是如何以及在哪裏傳遞額外的參數,以便我可以在窗體中處理查詢,因此它只會列出來自特定項目的用戶。Django中ManyToManyField的具有特定參數的窗體中自定義查詢

添加用戶

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) 

回答

3

您可以通過初始用戶查詢集,形成這樣的:

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

而且,你不需要調用project.save()project.contributors.add(user)已經進行查詢並增加M2M連接

+0

酷!我沒有想出這個。我自己測試了它。它要簡單得多,而且似乎更好。謝謝,我也學到了! – Jayground

+0

回覆你刪除的問題)它會返回所有在Project模型中與項目連接的用戶。 SQL查詢將如下所示:'SELECT * FROM「auth_user」INNER JOIN「projects_project」ON(「auth_user」。「id」=「projects_project」。「user_id」)WHERE「projects_project」。「id」= 1' – devxplorer

+0

謝謝,這是迄今爲止最簡單的解決方案,正是我所期待的。它實際上幫助我從views.py中移除了一些函數並簡化了代碼。我不知道你可以從forms.py之外操作窗體,我正在尋找如何將參數傳遞給forms.py中的窗體本身。呃...新手,對吧? :P – Ablivion

2

我決定幫助那些在本週末使用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}) 

網址。 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) 

然後初始化打算什麼數據通過重寫初始化方法形式展現。

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

你可以這樣過濾,因爲用戶和項目是N:N的關係。

我希望我能正確理解你的問題,並給你適當的答案:)我們的旅程與Django祝你好運!和平!

+0

你好,謝謝你的回覆。我測試了你的答案,但是我去了devxplorer,因爲它更簡單。雖然在這個特定的例子中並不需要,但這實際上可能會在諸如論壇的未來應用中派上用場。 – Ablivion

+0

是的,這是真的,devxplorer的答案更簡單,更好。我還了解到,有簡單的方法@devxplorer,但如果你使用基於類的視圖的通用形式呢?我認爲這將是不同的情況。我認爲你需要使用get_form_kwargs和init方法或更多來做到這一點。你不是嗎? – Jayground