2012-03-16 11 views
6

Mam problemy z ograniczaniem opcji do wyboru w zestawie. Mam następujące modele: Pracownicy, Dział, Projekt, Typ projektu, Członkostwo i Rola. Pracownik może dodawać/usuwać role, które odgrywają dla danego projektu departamentów w formularzu, formularz powinien ograniczyć wybór projektów do tylko tych należących do działu, do którego pracownik należy.django: Jak ograniczyć opcje pól w formularzu?

MODELE:

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",),) 

Widok:

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

Prawy obecnie UE może wybrać rolę do odegrania dla każdego projektu działów. To działając tak:

Opcje projektu:

Projects.objects.all() 

Chcę ograniczyć projekty z czymś takim: Projekt LIMIT CHOCIES DO:

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

[To przepełnienie stosu pytanie] (http://stackoverflow.com/questions/622982/django-passing-custom-form-parameters-to-formset) jest dość podobny. Istnieją dwa podejścia, które działają. 1) utwórz formularz, który bierze pracownika jako argument w jego metodzie "__init__" i użyj funkcji curry. 2) Zbuduj klasę formularza w funkcji widoku.Jeśli nie musisz ponownie używać formularza w innym miejscu, łatwiej jest znaleźć drugie podejście. – Alasdair

+0

nowość dla Pythona, czy struktura klasy formularza w widoku jest taka sama, jak w modelu model.py? – thedeepfield

+0

Rozszerzyłem mój komentarz jako odpowiedź poniżej. – Alasdair

Odpowiedz

7

Ten Stack Overflow question jest dość podobny. Podoba mi się podejście Mateusza, w którym dynamicznie budujesz formę w funkcji, która ma dostęp do pracownika poprzez zamknięcie. W twoim przypadku, chcesz coś takiego:

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

czy klasa MembershipForm ma być w widoku lub w modelu? – thedeepfield

+0

Występuje błąd z informacją, że funkcja "return" na zewnątrz – thedeepfield

+0

Formularze nie należą do 'models.py'. W większych aplikacjach Django czasami masz moduł 'forms.py'. W tym przypadku możesz umieścić funkcję 'make_membership_form' w' views.py', jeśli chcesz. – Alasdair

3

EDIT

Darn . Wszystko to pisząc, ponieważ przegapiłem jedną część kodu;). Jak wspomina @Alasdair w komentarzach, wykluczyłeś department z formularza, więc możesz ograniczyć to za pomocą Django. Mam zamiar opuścić moją oryginalną odpowiedź, na wszelki wypadek, może to pomóc komuś innemu.

Dla okoliczności, wszystko czego potrzebujesz to:

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) 

A następnie:

MembershipFormSet = modelformset_factory(Membership, form=MembershipForm, exclude=('department', 'employee'),) 

Oryginalny odpowiedzi (dla potomnych)

nie można ograniczyć w ten Django, ponieważ wartość dla działu jest zmienna, a zatem lista projektów może się różnić w zależności od tego, który departament jest wybrany na stronie nt. Aby sprawdzić poprawność formularza, musisz podać wszystkie możliwe projekty, które mogą być dozwolone dla Django, więc jedyną opcją jest AJAX.

Utwórz widok, który zwróci odpowiedź JSON składającą się z projektów dla określonego działu wprowadzonego do widoku. Coś wzdłuż linii:

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') 

Następnie utwórz trochę JavaScript, aby pobrać ten pogląd, gdy polu Wybierz dział ulega zmianie:

(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

'dział' nie podlega zmianie - uwaga' exclude = ('wydział', 'pracownik'),) '. – Alasdair

+0

OMG DZIĘKUJEMY, utknąłem w tej sprawie przez tydzień. Widziałem podobną odpowiedź, ale nigdy nie mogłem w pełni zrozumieć, co się dzieje. czy możesz mi powiedzieć, co oznacza ten kreator kodowania? referencje? – thedeepfield

+0

Ponadto, mój element wyjściowy ma dodatkowy pusty formularz do tworzenia nowego wpisu członkowskiego. Jednak pole projektu w tym nowym formularzu nie zawiera żadnych opcji ... Dlaczego brakuje moich wyborów? – thedeepfield

Powiązane problemy