I'm having problems limiting the selectable choices in a formset. I have the following models: Employees, Department, Project, Projecttype, Membership, and Role. An employee can add/remove the roles that they play for a given departments project in the formset, the form should limit the selectable projects to only those belonging to the department that the employee belongs to.
MODELS:
class Department(models.Model):
name = models.CharField(max_length=20)
def __unicode__(self):
return self.name
class Employee(models.Model):
fname = models.CharField(max_length=15)
department = models.ForeignKey(Department)
def __unicode__(self):
return self.fname
class Projecttype(models.Model):
name = models.CharField(max_length=20)
def __unicode__(self):
return self.name
class Project(models.Model):
projecttype = models.ForeignKey(Projecttype)
department = models.ForeignKey(Department)
members = models.ManyToManyField(Employee, through='Membership')
def __unicode__(self):
return "%s > %s" % (self.department, self.projecttype)
class Role(models.Model):
name = models.CharField(max_length=20)
def __unicode__(self):
return self.name
class Membership(models.Model):
project = models.ForeignKey(Project, null=True)
department = models.ForeignKey(Department)
employee = models.ForeignKey(Employee)
role = models.ManyToManyField(Role, blank=True, null=True)
class Meta:
unique_together = (("project", "employee",),)
VIEW:
def employee_edit(request, employee_id):
i = get_object_or_404(Employee, pk=employee_id)
MembershipFormSet = modelformset_factory(Membership, exclude=('department', 'employee'),)
f = MembershipFormSet(queryset=Membership.objects.filter(employee=i),)
return render_to_response('gcs/edit.html', {'item': i, 'formset': f, }, context_instance=RequestContext(request))
Right now an EU can select a role to play for any departments project. It's acting like this:
Project Options:
Projects.objects.all()
I want to limit the projects with something like this: LIMIT PROJECT CHOCIES TO:
Projects.objects.filter(department=i.department)
This Stack Overflow question is fairly similar. I like the approach of Matthew's answer, where you build the form dynamically in a function that has access to the employee via closure. In your case, you want something like:
EDIT
Darn. All that typing because I missed one part of the code ;). As @Alasdair mentions in the comments, you've excluded
department
from the form, so you can limit this with Django. I'm going to leave my original answer, though, just in case it might help someone else.For your circumstances, all you need is:
And, then:
Original Answer (for posterity)
You can't limit this in Django, because the value for department is changeable, and thus the list of projects can vary depending on which particular department is selected at the moment. In order to validate the form, you'll have to feed all possible projects that could be allowed to Django, so your only option is AJAX.
Create a view that will return a JSON response consisting of projects for a particular department fed into the view. Something along the lines of:
Then, create a bit of JavaScript to fetch this view whenever the department select box is changed: