EDIT
darn. All this prints because I missed one piece of code;). As @Alasdair mentions in the comments, you excluded department
from the form, so you can limit it with Django. I am going to leave my initial answer, although just in case this may help someone else.
In your circumstances, all you need is:
class MembershipForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(MembershipForm, self).__init__(*args, **kwargs) self.fields['project'].queryset = self.fields['project'].queryset.filter(department_id=self.instance.department_id)
And then:
MembershipFormSet = modelformset_factory(Membership, form=MembershipForm, exclude=('department', 'employee'),)
Original answer (for posterity)
You cannot limit this in Django, because the value for the department is variable, and therefore, the list of projects may vary depending on which specific department is currently selected. To validate the form, you will need to submit all possible projects that Django may allow, so your only option is AJAX.
Create a view that returns a JSON response consisting of projects for a specific department filed in the view. Sort of:
from django.http import HttpResponse, HttpResponseBadRequest from django.shortcuts import get_list_or_404 from django.utils import simplejson def ajax_department_projects(request): department_id = request.GET.get('department_id') if department_id is None: return HttpResponseBadRequest() project_qs = Project.objects.select_related('department', 'project_type') projects = get_list_or_404(project_qs, department__id=department_id) data = [] for p in projects: data.append({ 'id': p.id, 'name': unicode(p), }) return HttpResponse(simplejson.dumps(data), mimetype='application/json')
Then create some JavaScript to get this view whenever the department selection field changes:
(function($){ $(document).ready(function(){ var $department = $('#id_department'); var $project = $('#id_project'); function updateProjectChoices(){ var selected = $department.val(); if (selected) { $.getJSON('/path/to/ajax/view/', {department_id: selected}, function(data, jqXHR){ var options = []; for (var i=0; i<data.length; i++) { output = '<option value="'+data[i].id+'"'; if ($project.val() == data[i].id) { output += ' selected="selected"'; } output += '>'+data[i].name+'</option>'; options.push(output); } $project.html(options.join('')); }); } } updateProjectChoices(); $project.change(updateProjectChoices); }); })(django.jQuery);