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)