Using Django's FilteredSelectMultiple widget

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)