0

我正在使用我的 3 层模型实现嵌套内联,并且目前正在使用它。但是,即使我传递了正确的实例,我也无法限制我relevantindicator的下拉选项。当前relevantindicator在下拉选择中显示表中的所有值。我想将值限制为仅与disease实例关联的值。有没有办法做到这一点?

我正在使用正确的方法在 Djangohttp://yergler.net/blog/2009/09/27/nested-formsets-with-django/中保存嵌套表单集作为参考。

模型.py

class Disease(models.Model):
    disease = models.CharField(max_length=255)

class Indicator(models.Model):
    relevantdisease = models.ForeignKey(Disease)       
    indicator = models.CharField(max_length=255)

class IndicatorValue(models.Model):
    relevantindicator = models.ForeignKey(Indicator)
    indicator_value = models.CharField(max_length=50)

表格.py

class BaseIndicatorFormSet(BaseInlineFormSet):

     def __init__(self, *args, **kwargs):
        try:
            instance = kwargs.pop('instance')
        except KeyError:
            super(BaseIndicatorFormSet, self).__init__(*args, **kwargs)

     def save_new(self, form, commit=True):
        instance = super(BaseIndicatorFormSet, self).save_new(form, commit=commit)

        form.instance = instance

        for nested in form.nested:
            nested.instance = instance

        for cd in nested.cleaned_data:
            cd[nested.fk.name]=instance

        return instance
...

     def add_fields(self,form,index):
        super(BaseIndicatorFormSet, self).add_fields(form, index)

        try:
            instance = self.get_queryset()[index]
            pk_value = instance.pk

        except IndexError:
            instance=None
            pk_value = hash(form.prefix)

        form.nested = [
            IndicatorValueFormSet(
                disease = instance,
                queryset = IndicatorValue.objects.filter(relevantindicator = pk_value), 
                prefix = 'value_%s' % pk_value)]


class BaseIndicatorValueFormSet(BaseModelFormSet):

    def __init__(self, disease, *args, **kwargs):
        super(BaseIndicatorValueFormSet, self).__init__(*args, **kwargs)
        self.disease = disease     

    def save_new(self, form, commit=True):
        instance = form.save(commit=False)
        instance.disease = self.disease
        if commit:
           instance.save()
        return instance

    def save_existing(self, form, instance, commit=True):
        return self.save_new(form, commit)

class IndicatorValueForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        try:
            disease_obj = kwargs.pop('disease')
        except KeyError:
            super(IndicatorValueForm, self).__init__(*args, **kwargs)
            return

        super(IndicatorValueForm, self).__init__(*args, **kwargs)
        queryset = Indicator.objects.filter(relevantdisease =disease_obj)
        self.fields['relevantindicator'].queryset = queryset


disease_obj = get_object_or_404(Disease, pk=2) #hard-wired
CurriedForm = formset_factory(IndicatorValueForm, extra=3)
CurriedForm.form = staticmethod(curry(IndicatorValueForm, disease = disease_obj))
IndicatorValueFormSet = inlineformset_factory(Indicator, IndicatorValue,   formset=BaseIndicatorValueFormSet, form = CurriedForm, extra=3)
IndicatorFormSet = inlineformset_factory(Disease, Indicator, formset=BaseIndicatorFormSet, extra=0)

视图.py

 disease = get_object_or_404(Disease, pk=disease_id)

 if request.method == "POST":
      formset = IndicatorFormSet(request.POST, instance=disease)

    if formset.is_valid():
       rooms = formset.save_all()
       return HttpResponseRedirect(reverse('option', kwargs={'disease_id':disease_id}))
 else:
       formset = IndicatorFormSet(instance=disease)

context = {'disease': disease, 'indicators': formset, 'hide_breadcrumb':hide_breadcrumb}
   return render_to_response('valdrui.html',context, context_instance=RequestContext(request))

模板.html

  {% if relevantindicator.nested %}
  {% for formset in relevantindicator.nested %}
  {{ formset.as_table }}
  {% endfor %}
  {% endif %}

更新 我的感觉是我需要将疾病实例从 form.nested 传递到 BaseIndicatorValueFormSet。但它似乎不起作用。

提供清晰的屏幕截图。

relatedindicator 提供了一个下拉菜单

relatedindicator 提供了一个下拉菜单

当有indicator_value 时,选择正确的相关指标。 但是,当添加一个新的indicator_vale 时,所有相关疾病的所有相关指标都可用。 我想将相关指标选择限制为相关疾病(疾病实例)

当有indicator_value 时,选择正确的相关指标。但是,当添加新的indicator_value 时,所有相关疾病的所有相关指标都可用。我想将相关指标选择限制为相关疾病(疾病实例)

更新 2:我必须instance在 BaseIndicatorFormSet 下定义一个def __init__. 我还需要在 forms.py 中定义表单,因为BaseIndicatorFormSet调用IndicatorValueFormSet。该实例当前是硬连线的,只是为了查看模板是否会呈现。不幸的是,模板中的表单不会呈现,但也不会产生任何错误。我不知道为什么,因为没有产生错误。

4

2 回答 2

0

尝试制作一个自定义 ModelForm 来过滤您的相关指标字段:

class IndicatorValueForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        try:
            disease_obj = kwargs.pop('disease')
        except KeyError:
            super(IndicatorValueForm, self).__init__(*args, **kwargs)
            return
        super(IndicatorValueForm, self).__init__(*args, **kwargs)
        queryset = Indicator.objects.filter(relevantdisease =disease_obj)
        self.fields['relevantindictor'].queryset = queryset

这将使用您希望过滤的疾病对象修改 Forms init方法,并将其添加到 kwargs.xml 中。

要使用它,我们需要使用 curry 方法将 Disease 对象传入表单:

disease_obj = <your-disease-instance>
CurriedForm = staticmethod(curry(IndicatorValueForm, disease = disease_obj))
IndicatorValueFormSet = inlineformset_factory(Indicator, IndicatorValue,   formset=BaseIndicatorValueFormSet, form = CurriedForm, extra=3)

现在您的下拉菜单应该只显示按疾病过滤的指标。

于 2013-09-03T19:01:59.430 回答
0

这是一个完整的 forms.py 你可以基于你的代码

from django import forms
from django.forms.formsets import DELETION_FIELD_NAME
from django.forms.models import BaseInlineFormSet, BaseModelFormSet, inlineformset_factory

from .models import Disease, Indicator, IndicatorValue


class BaseIndicatorFormSet(BaseInlineFormSet):

    def save_new(self, form, commit=True):
        instance = super(BaseIndicatorFormSet, self).save_new(form, commit=commit)
        form.instance = instance

        for nested in form.nested:
            nested.instance = instance

        for cd in nested.cleaned_data:
            cd[nested.fk.name]=instance

        return instance

    def add_fields(self, form, index):
        super(BaseIndicatorFormSet, self).add_fields(form, index)

        try:
            instance = self.get_queryset()[index]
            pk_value = instance.pk
        except IndexError:
            instance=None
            pk_value = hash(form.prefix)

        form.nested = [
            IndicatorValueFormSet(
                instance=instance,
                disease=instance.relevantdisease,
                prefix='value_%s' % pk_value,
                queryset=IndicatorValue.objects.filter(relevantindicator=pk_value),
            )
        ]

    def should_delete(self, form):
        """
        Convenience method for determining if the form's object will
        be deleted; cribbed from BaseModelFormSet.save_existing_objects.
        """

        if self.can_delete:
            raw_delete_value = form._raw_value(DELETION_FIELD_NAME)
            should_delete = form.fields[DELETION_FIELD_NAME].clean(raw_delete_value)
            return should_delete

        return False

    def save_all(self, commit=True):
        """
        Save all formsets and along with their nested formsets.
        """

        # Save without committing (so self.saved_forms is populated)
        # - We need self.saved_forms so we can go back and access
        #    the nested formsets
        objects = self.save(commit=False)

        # Save each instance if commit=True
        if commit:
            for o in objects:
                o.save()

        # save many to many fields if needed
        if not commit:
            self.save_m2m()

        # save the nested formsets
        for form in set(self.initial_forms + self.saved_forms):
            if self.should_delete(form): continue

            for nested in form.nested:
                nested.save(commit=commit)


class BaseIndicatorValueFormSet(BaseInlineFormSet):

    def __init__(self, disease, *args, **kwargs):
        self.disease = disease
        super(BaseIndicatorValueFormSet, self).__init__(*args, **kwargs)

    def _construct_form(self, i, **kwargs):
        form = super(BaseIndicatorValueFormSet, self)._construct_form(i, **kwargs)
        form.fields['relevantindicator'].parent_instance = self.disease
        return form

    def save_new(self, form, commit=True):
        instance = form.save(commit=False)
        instance.disease = self.disease
        if commit:
           instance.save()
        return instance

    def save_existing(self, form, instance, commit=True):
        return self.save_new(form, commit)


IndicatorValueFormSet = inlineformset_factory(
    Indicator,
    IndicatorValue,
    formset=BaseIndicatorValueFormSet,
    extra=3
)

IndicatorFormSet = inlineformset_factory(
    Disease,
    Indicator,
    formset=BaseIndicatorFormSet,
    extra=0
)
于 2013-08-30T13:25:24.907 回答