2010-04-05 2 views
7

Sto provando a usare inlineformset_factory per generare un formset. I miei modelli sono definite come:Filtro Queryset in 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) 

a mio avviso ho:

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

ma voglio limitare il campo Measurement.subject ai soli soggetti definiti nel set di query Experiment.subjects. Ho provato un paio di modi diversi per farlo, ma non sono sicuro di quale sia il modo migliore per farlo. Ho provato a scavalcare la classe BaseInlineFormset con un nuovo queryset, ma non riuscivo a capire come passare correttamente il parametro dell'esperimento.

risposta Aggiornato (ho incluso anche le informazioni da qui come un modo per passare il parametro per il 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

Non ho mai sentito parlare di un curry() in Python prima, sicuramente non è integrato. EDIT: ... Ahh .. Ho appena notato il post collegato: da django.utils .funzionale import curry – Rich

+0

Funziona ancora in Django 1.5? Viene visualizzato il seguente errore: __init __() ha ottenuto un argomento di parole chiave imprevisto 'empty_permitted' – Puzzled79

risposta

3

(modifica: non ha letto correttamente i blocchi di codice, qui dovrebbe essere una soluzione al tuo problema):

Credo che hai bisogno: 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 
) 

rilegatura a formset viene fatto con il parametro modulo.

+0

Ho provato questo ma non ho avuto molta fortuna. Qual è lo scopo degli elementi filtro e prefisso? – Dave

+0

Modificata la mia risposta di ieri, modelchoicefield dovrebbe avere gli ingredienti per una soluzione. –

+0

Ho modificato il mio codice (vedi l'aggiunta nella domanda) ma ora l'errore è al momento del salvataggio. L'errore è ora "Impossibile assegnare" ":" Measurement.experiment "deve essere un'istanza di" Esperimento "." – Dave

1

Ho avuto lo stesso problema (inizializza inlineforms con un numero limitato di valori possibili) e la risposta aggiornata funziona alla grande. Grazie per quello. Comunque, c'è qualcosa che potrebbe essere fatto meglio, penso, ma non ho idea di come farlo. Il nuovo numero di questa soluzione è che si colpisce il database in ogni inlineform: invece di utilizzare lo stesso set di query in tutti gli stessi campi, ricalcola ogni volta in questa linea:

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

Ho ragione in questo numero o c'è qualche magia pigro-django dietro al cofano? Se ho ragione, come potrei evitare il possibile numero di colpi al DB? Pedro

+0

Per evitare i colpi al DB, basta circondare il filtro del queryset usare @ [ŁukaszKorzybski's [trucco] (http://stackoverflow.com/a/2108902/623735) - 'if not hasattr (self, '_queryset'):' – hobs