2010-04-05 24 views
7

Estoy tratando de usar inlineformset_factory para generar un formset. Mis modelos se definen como:Filter Queryset en 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) 

en mi opinión que tengo:

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

pero yo desee restringir el campo Measurement.subject sólo a los sujetos definidos en el conjunto de consultas Experiment.subjects. He intentado un par de formas diferentes de hacerlo, pero no estoy seguro de cuál es la mejor manera de lograrlo. Traté de sobrepasar la clase BaseInlineFormset con un nuevo conjunto de preguntas, pero no pude averiguar cómo pasar correctamente el parámetro del experimento.

respuesta Actualizado (I también se incluyó la información de aquí como una manera de pasar el parámetro para el juego de formularios 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

nunca he oído hablar de un curry() en Python antes, definitivamente no es un sistema incorporado en EDIT:. ... Ahh .. Acabo de notar el puesto vinculados: En django.utils .functional import curry – Rich

+0

¿Esto todavía funciona en Django 1.5? Obtengo el siguiente error: __init __() Obtuve un argumento inesperado de palabra clave 'empty_permitted' – Puzzled79

Respuesta

3

(edite: no leyó los bloques de código correctamente, aquí debería haber una solución a su problema):

creo que necesita: 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 
) 

obligatorio para formset se realiza mediante el parámetro formulario.

+0

Intenté esto pero no mucha suerte. ¿Cuál es el propósito de los elementos de filtro y prefijo? – Dave

+0

Editado ayer mi respuesta, modelchoicefield debería tener los ingredientes para una solución. –

+0

He alterado mi código (vea la adición en la pregunta) pero ahora el error se produce al guardar. El error ahora es "No se puede asignar" ":" Measurement.experiment "debe ser una instancia de" Experiment ". – Dave

1

Pasé por el mismo problema (inicializar líneas en línea con valores posibles limitados), y la respuesta actualizada funciona muy bien. Gracias por eso. De todos modos, hay algo que podría hacerse mejor, creo, pero no tengo ni idea de cómo hacerlo. El nuevo número de esta solución es que usted golpea la base de datos en cada inlineform: en lugar de utilizar el mismo conjunto de consultas en todos los mismos campos, vuelve a calcular cada vez que en esta línea:

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

Estoy en lo cierto en este asunto o Hay algo de pereza-magia django detrás del capó? Si estoy en lo cierto, ¿cómo podría evitar los (posibles cientos) de visitas al DB? Saludos, Pedro

+0

Para evitar las visitas a la base de datos, simplemente rodee el filtro de conjunto de consultas use @ [trukaszKorzybski's] [truco] (http://stackoverflow.com/a/2108902/623735) - 'if not hasattr (self, '_queryset'):' – hobs

Cuestiones relacionadas