在Django的inlineformset_factory中过滤Queryset

7

我正在尝试使用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)

在我看来,我有:

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

但我希望限制Measurement.subject字段仅限于Experiment.subjects查询集中定义的主题。 我尝试了几种不同的方法,但我不太确定实现这一目标的最佳方式是什么。我试图用新的查询集覆盖BaseInlineFormset类,但无法弄清楚如何正确传递实验参数。 更新的答案(我还包括了此处的信息作为将参数传递给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)

我以前从未听说过Python中的curry(),它绝对不是内置函数。编辑:啊...我刚刚注意到链接的帖子:from django.utils.functional import curry。 - Rich
这在Django 1.5中还有效吗?我收到了以下错误:__init __()收到了一个意外的关键字参数'empty_permitted' - Puzzled79
2个回答

3

我相信你需要的是: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
  )

使用表单参数将数据绑定到表单集。


我尝试了这个,但没有太多的运气。过滤器和前缀元素的目的是什么? - Dave
昨天我编辑了我的答案,modelchoicefield 应该有解决方案的要素。 - h-kippo
我修改了我的代码(请参见问题中的添加),但现在保存时出现错误。错误现在是“无法分配“<Measurement:Measurement object>”:“Measurement.experiment”必须是“Experiment”实例。” - Dave
抱歉,无法提供帮助。您问题中更新的代码并未使用ModelChoiceField方法。也许我没有理解您问题的根本原因,因为我的建议对您没有用处。 - h-kippo

1

我曾经遇到过同样的问题(使用有限可能值初始化inlineforms),更新后的答案非常好。谢谢。 不过,我认为有些事情可以做得更好,但我不知道如何实现。该解决方案中的新问题是每个inlineform都会访问数据库:而不是在所有相同字段中使用相同的查询集,在此行中每次重新计算:

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

我在这个问题上是正确的,还是有一些懒惰的Django魔法在后台运行?如果我是正确的,那么我该如何避免对数据库的(可能达到百次)访问? 问候, Pedro


为了避免对数据库的访问,只需使用@ŁukaszKorzybski的技巧来包围查询集过滤器-- if not hasattr(self, '_queryset'): - hobs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接