2012-03-16 3 views
6

formset의 선택 가능한 선택을 제한하는 데 문제가 있습니다. 저는 다음과 같은 모델을 가지고 있습니다 : 직원, 부서, 프로젝트, 프로젝트 유형, 회원 및 역할. 직원은 formset에서 주어진 부서 프로젝트에 대해 수행하는 역할을 추가/제거 할 수 있습니다. 양식은 직원이 속한 부서에 속한 프로젝트로만 선택 가능한 프로젝트를 제한해야합니다.django : 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)) 

는 현재 유럽 연합 (EU)은 어떤 부서 프로젝트의 역할을 선택할 수 있습니다. 그것은이처럼 행동 것 :

프로젝트 옵션 :

Projects.objects.all() 

나는 이런 식으로 뭔가 함께 프로젝트를 제한하려면 : LIMIT 프로젝트 CHOCIES TO :

Projects.objects.filter(department=i.department) 
+0

[이 스택 오버플로 질문] (http://stackoverflow.com/questions/622982/django-passing-custom-form-parameters-to-formset)이 상당히 있습니다 : 귀하의 경우에, 당신은 뭔가처럼 원하는 비슷한. 두 가지 접근 방식이 있습니다. 1)'__init__' 메쏘드에서 employee를 인수로 취하고 카레 함수를 사용하는 폼을 생성하십시오. 2) 뷰 기능에서 양식 클래스를 빌드하십시오.양식을 다른 곳에서 다시 사용할 필요가 없다면 두 번째 방법을 더 쉽게 사용할 수 있습니다. – Alasdair

+0

python을 처음 사용하는 경우 model.py와 마찬가지로 뷰에서 양식 클래스를 구성합니까? – thedeepfield

+0

답변으로 내 의견을 확장했습니다. – Alasdair

답변

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)) 
+0

은 MembershipForm 클래스가 뷰 또는 모델에 있다고 가정합니까? – thedeepfield

+0

함수 외부에서 'return'이라고 말하면 오류가 발생합니다. – thedeepfield

+0

양식은 실제로는 models.py에 속해 있지 않습니다. 더 큰 Django 응용 프로그램에는 때때로 'forms.py'모듈이 있습니다. 이 경우, 당신이 원한다면'views.py'에'make_membership_form' 함수를 넣을 수 있습니다. – Alasdair

3

편집

터무니 . 코드의 한 부분을 놓치기 때문에 타이핑하는 모든 것;). @Alasdair가 주석에서 언급했듯이 department을 양식에서 제외 시켰으므로 장고로이를 제한 할 수 있습니다. 나는 원래의 답을 남겨 두지 만, 다른 사람을 도울 수 있기를 바랍니다. 다음,

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는 부서 값이 변경 가능하기 때문에 프로젝트 목록은 특정 부서가 mome에서 선택되는 방식에 따라 다를 수 있습니다 nt. 양식의 유효성을 검사하려면 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') 

그런 다음,이보기를 가져 오기 위해 자바 스크립트의 비트를 만들 :

(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); 
+0

'department'는 변경 가능하지 않습니다. 'exclude = ('department ','employee '))'에 유의하십시오. – Alasdair

+0

OMG, 1 주일 동안이 문제에 고생했습니다. 필자는 비슷한 대답을 던져 보았지만 계속 진행되는 것을 완전히 이해할 수는 없었습니다. 이 코딩 마법사가 무엇을 의미하는지 말해 주시겠습니까? 참조? – thedeepfield

+0

또한, 내 직역에는 새 멤버십 항목을 만들기위한 추가 빈 양식이 있습니다. 그러나이 새로운 형태의 프로젝트 필드에는 선택 사항이 없습니다 ... 왜 지금 내 선택이 누락 되었습니까? – thedeepfield