In Django's admin views there's a form widget that's useful for adding, for example, many groups or permissions to a user in one action. There isn't much official documentation on this, but it's possible to use it in your own forms.
If you have a model with a ManyToManyField, you can set up FilteredSelectMultiple using a ModelForm.
In DMT, where I was
using this, we had a Project that was tied to users (personnel)
indirectly through a WorksOn object. The Project class already
had a all_users_not_in_project()
method for looking
up users that could be added to this project, and it returns
a list, not a QuerySet.
So, just to illustrate how I did this:
from django.contrib.admin.widgets import FilteredSelectMultiple class ProjectPersonnelForm(forms.Form): class Media: # Django also includes a few javascript files necessary # for the operation of this form element. You need to # include <script src="/admin/jsi18n"></script> # in the template. css = { 'all': ('admin/css/widgets.css',) } def __init__(self, *args, **kwargs): pid = kwargs.pop('pid') r = super(ProjectPersonnelForm, self).__init__( *args, **kwargs) p = Project.objects.get(pk=pid) qs = UserProfile.objects.filter( pk__in=[u.pk for u in p.all_users_not_in_project()] ).order_by( Lower('fullname') ).order_by( Lower('username')) self.fields['personnel'] = \ forms.ModelMultipleChoiceField( queryset=qs, widget=FilteredSelectMultiple( 'Personnel', is_stacked=False), label='') return r
Definitely a little messy. Oh well. At least I have some tests:
from django.test import TestCase from dmt.main.forms import ProjectPersonnelForm from dmt.main.tests.factories import ( UserProfileFactory, ProjectFactory ) class ProjectPersonnelFormTest(TestCase): def test_init(self): p = ProjectFactory() ProjectPersonnelForm(pid=p.pid) def test_personnel_present(self): u1 = UserProfileFactory() u2 = UserProfileFactory() u3 = UserProfileFactory() p = ProjectFactory() p.add_personnel(u3) f = ProjectPersonnelForm(pid=p.pid) personnel_in_form = \ f.fields.get('personnel').queryset.all() self.assertTrue(u1 in personnel_in_form) self.assertTrue(u2 in personnel_in_form) self.assertFalse(u3 in personnel_in_form) self.assertTrue( p.caretaker_user.userprofile in personnel_in_form)