我在限制formset中的可选选项时遇到问题。我有以下模型:员工,部门,项目,项目类型,成员资格和角色。员工可以在表单集中添加/删除他们为给定部门项目播放的角色,表单应该将可选项目限制为仅属于该员工所属部门的那些项目。
模型:
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",),)
查看:
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))
现在,欧盟可以为任何部门项目选择一个角色。它的表现如下:
项目选项:
Projects.objects.all()
我想用这样的方式限制项目:LIMIT PROJECT CHOCIES TO:
Projects.objects.filter(department=i.department)
答案 0 :(得分:7)
此Stack Overflow question非常相似。我喜欢Matthew的答案,你可以在一个通过闭包访问员工的函数中动态构建表单。在你的情况下,你需要像:
from django.http import HttpResponseRedirect
def make_membership_form(employee):
"""
Returns a Membership form for the given employee,
restricting the Project choices to those in the
employee's department.
"""
class MembershipForm(forms.ModelForm):
project = forms.ModelChoiceField(queryset=Projects.objects.filter(department=employee.department))
class Meta:
model = Membership
excludes = ('department', 'employee',)
return MembershipForm
def employee_edit(request, employee_id):
employee = get_object_or_404(Employee, pk=employee_id)
# generate a membership form for the given employee
MembershipForm = make_membership_form(employee)
MembershipFormSet = modelformset_factory(Membership, form=MembershipForm)
if request.method == "POST":
formset = MembershipFormSet(request.POST, queryset=Membership.objects.filter(employee=employee))
if formset.is_valid():
instances = formset.save(commit=False)
for member in instances:
member.employee = employee
member.department = employee.department
member.save()
formset.save_m2m()
# redirect after successful update
return HttpResponseRedirect("")
else:
formset = MembershipFormSet(queryset=Membership.objects.filter(employee=employee),)
return render_to_response('testdb/edit.html', {'item': employee, 'formset': formset, }, context_instance=RequestContext(request))
答案 1 :(得分:4)
修改强>
织补。所有打字因为我错过了代码的一部分;)。正如@Alasdair在评论中提到的那样,您已从表单中排除department
,因此您可以使用Django对此进行限制。不过,我会留下原来的答案,以防万一它可以帮助别人。
根据您的具体情况,您只需要:
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)
然后:
MembershipFormSet = modelformset_factory(Membership, form=MembershipForm, exclude=('department', 'employee'),)
原始答案(后代)
您不能在Django中对此进行限制,因为部门的值是可更改的,因此项目列表可能会根据当前选择的特定部门而有所不同。为了验证表单,您必须提供允许Django的所有可能项目,因此您唯一的选择是AJAX。
创建一个视图,该视图将返回一个JSON响应,该响应由供给视图的特定部门的项目组成。有点像:
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')
然后,每当更改部门选择框时,创建一些JavaScript以获取此视图:
(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);