2010-04-05 9 views
7

J'essaie d'utiliser inlineformset_factory pour générer un formset. Mes modèles sont définis comme:Jeu de queries dans 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) 

à mon avis j'ai:

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

mais je veux restreindre le champ Measurement.subject aux seuls sujets définis dans le Experiment.subjects queryset. J'ai essayé quelques manières différentes de faire ceci mais je suis un peu sûr que la meilleure manière d'accomplir ceci est. J'ai essayé de surcharger la classe BaseInlineFormset avec un nouveau jeu de requête, mais je n'ai pas pu déterminer comment passer correctement le paramètre de test.

réponse Mise à jour (je aussi inclus les informations d'ici comme un moyen de passer le paramètre à la 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

Je n'ai jamais entendu parler d'un curry() en Python avant, ce n'est certainement pas intégré. EDIT: ... Ahh .. Je viens de remarquer le post lié: de django.utils .functional import curry – Rich

+0

Cela fonctionne-t-il encore dans Django 1.5? Je reçois l'erreur suivante: __init __() a un argument mot-clé inattendu 'empty_permitted' – Puzzled79

Répondre

3

(edit: n'a pas lu les blocs de code correctement, voici une solution à votre problème):

Je crois que vous avez besoin: 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 
) 

Reliure à formset est fait en utilisant le paramètre de forme.

+0

J'ai essayé cela mais pas beaucoup de chance. Quel est le but des éléments de filtre et de préfixe? – Dave

+0

Edité ma réponse hier, modelchoicefield devrait avoir les ingrédients pour une solution. –

+0

J'ai modifié mon code (voir l'addition dans la question) mais maintenant l'erreur est sur la sauvegarde. L'erreur est maintenant "Impossible d'affecter" ":" Measurement.experiment "doit être une instance" Experiment "." – Dave

1

J'ai eu le même problème (initialiser des formes en ligne avec des valeurs possibles limitées), et la réponse mise à jour fonctionne très bien. Merci pour ça. De toute façon, il y a quelque chose qui pourrait être mieux fait, je pense, mais je n'ai aucune idée de comment y arriver. La nouvelle question dans cette solution est que vous appuyez sur la base de données dans chaque inlineform: au lieu d'utiliser la même queryset dans tous les mêmes champs, il recalcule à chaque fois dans cette ligne:

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

Ai-je raison dans ce numéro ou il y a de la paresse-django-magique derrière le capot? Si j'ai raison, comment pourrais-je éviter la (centaine) de hits à la DB? Salutations, Pedro

+0

Pour éviter les hits à la base de données, entourez simplement le filtre du jeu de requête @ ŁukaszKorzybski [trick] (http://stackoverflow.com/a/2108902/623735) - 'sinon has hastr (self, '_queryset'):' – hobs

Questions connexes