2010-04-05 16 views
7

Próbuję użyć inlineformset_factory do generowania zestawu formularzy. Moje modele są zdefiniowane jako:Filtr kwerendy w Django inlineformset_factory

class Measurement(models.Model): 
    subject = models.ForeignKey(Subject) 
    experiment = models.ForeignKey(Experiment) 
    assay = models.ForeignKey(Assay) 
    values = models.CommaSeparatedIntegerField(blank=True, null=True) 

class Experiment(models.Model): 
    date = models.DateField() 
    notes = models.TextField(max_length = 500, blank=True) 
    subjects= models.ManyToManyField(Subject) 

moim zdaniem mam:

def add_measurement(request, experiment_id): 
    experiment = get_object_or_404(Experiment, pk=experiment_id) 
    MeasurementFormSet = inlineformset_factory(Experiment, Measurement, extra=10, exclude=('experiment')) 
    if request.method == 'POST': 
     formset = MeasurementFormSet(request.POST,instance=experiment) 
     if formset.is_valid(): 
      formset.save() 
      return HttpResponseRedirect(experiment.get_absolute_url()) 
    else: 
     formset = MeasurementFormSet(instance=experiment) 
    return render_to_response("data_entry_form.html", {"formset": formset, "experiment": experiment }, context_instance=RequestContext(request)) 

ale chcę, aby ograniczyć pole Measurement.subject się tylko przedmioty określone w queryset Experiment.subjects. Próbowałem na kilka różnych sposobów, ale nie jestem pewien, jak najlepiej to osiągnąć. Próbowałem przeładować klasę BaseInlineFormset nowym zestawem zapytań, ale nie mogłem wymyślić, jak poprawnie przekazać parametr eksperymentu.

Updated odpowiedź (ja również informacje z tutaj jako sposób przekazać parametr do formset link):

views.py

def add_measurement(request, experiment_id):  
    experiment = get_object_or_404(Experiment, pk=experiment_id)  
    MeasurementFormSet = inlineformset_factory(Experiment, Measurement, extra=10, can_delete=True, form=MeasurementForm)  
    MeasurementFormSet.form = staticmethod(curry(MeasurementForm, experiment=experiment)) 
    if request.method == 'POST': 
     formset = MeasurementFormSet(request.POST)  
     if formset.is_valid(): 
     formset.save() 
     return HttpResponseRedirect(experiment.get_absolute_url())  
    else: 
     formset = MeasurementFormSet() 
     return render_to_response("data_entry_form.html", {"formset": formset, "experiment": experiment }, context_instance=RequestContext(request)) 

forms.py

class MeasurementForm(ModelForm): 
    class Meta: 
     model = Measurement 
    def __init__(self, *args, **kwargs): 
     experiment = kwargs.pop('experiment') 
     super(MeasurementForm, self).__init__(*args, **kwargs) 
     self.fields["subject"].queryset = Subject.objects.filter(experiment=experiment) 
+0

Nigdy wcześniej nie słyszałem o curry() w Pythonie, zdecydowanie nie jest ono wbudowane. EDYTOWANIE: ... Ahh .. Właśnie zauważyłem powiązany wpis: from django.utils .functional import curry – Rich

+0

Czy to nadal działa w Django 1.5? Otrzymuję następujący błąd: __init __() otrzymałem nieoczekiwany argument słowa kluczowego "empty_permitted" – Puzzled79

Odpowiedz

3

(edytuj: nie czytałem poprawnie bloków kodu, tutaj powinno być rozwiązaniem twojego problemu):

wierzę trzeba: http://docs.djangoproject.com/en/dev/ref/forms/fields/#modelchoicefield

Forms.py:

class MeasurementForm(ModelForm): 
subject = forms.ModelChoiceField(queryset = Expirement.objects.all()) 
class Meta: 
    model = Measurement 

Views.py:

inlineformset_factory(
    Experiment, Measurement, extra=10, 
    exclude=('experiment'), form=MeasurementForm 
) 

wiązanie z formset odbywa się za pomocą parametru formularza.

+0

Próbowałem tego, ale nie miałem szczęścia. Jaki jest cel filtra i elementów prefiksu? – Dave

+0

Zmieniono moją odpowiedź wczoraj, modelchoicefield powinien mieć składniki do rozwiązania. –

+0

Zmieniłem mój kod (patrz dodatek do pytania), ale teraz błąd dotyczy zapisywania. Błąd jest teraz "Nie można przypisać" ":" Measurement.experiment "musi być instancją" Experiment "." – Dave

1

Przeszedłem przez ten sam problem (zainicjuję inlineforms z ograniczonymi możliwymi wartościami), a Zaktualizowana odpowiedź działa świetnie. Dziękuję za to. W każdym razie, jest coś, co można zrobić lepiej, myślę, ale nie mam pojęcia, jak to zrobić. Nowa emisja w tego rozwiązania jest to, że trafisz do bazy danych w każdej inlineform: zamiast przy użyciu tego samego queryset we wszystkich tych samych dziedzinach, przelicza go za każdym razem w tej linii:

self.fields["subject"].queryset = Subject.objects.filter(experiment=experiment) 

mam rację w tej kwestii lub za kapturem kryje się leniwy-django-magia? Jeśli mam rację, jak mogę uniknąć (możliwych stu) trafień do DB? Pozdrowienia, Pedro

+0

Aby uniknąć trafień do DB, wystarczy otoczyć filtr kwerendy używając @ ŁukaszKorzybski's [trick] (http://stackoverflow.com/a/2108902/623735) - 'if not hasattr (self, '_queryset'):' – hobs