I am implementing nested inlines with my 3-tiered model and currently having it functional. However, I can't limit my relevantindicator
drop-down choices even though I am passing the correct instance. Currently relevantindicator
displays all values in the table in the drop-down selection. I'd like to limit the values to only those associated with the disease
instance. Is there a way to do that?
I'm using Correct way to save nested formsets in Django and http://yergler.net/blog/2009/09/27/nested-formsets-with-django/ as references.
models.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)
forms.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)
views.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))
template.html
{% if relevantindicator.nested %}
{% for formset in relevantindicator.nested %}
{{ formset.as_table }}
{% endfor %}
{% endif %}
Update My feeling is that I need to pass the disease instance from form.nested down to BaseIndicatorValueFormSet. But it does not seem to be working.
Screenshots to provide clarity.
relevantindicator provides a drop-down
When there is a indicator_value, the correct relevantindicator is selected. However, when adding a new indicator_value, all relevantindicator for all relevantdiseases are available. I'd like to limit the relevantindicator choices to the relevantdiseases (the disease instance)
Update 2: I had to define an instance
in BaseIndicatorFormSet under def __init__
. I also needed to define the forms in forms.py since BaseIndicatorFormSet
calls IndicatorValueFormSet
. The instance is currently hard-wired, just to see if the template will render. Unfortunately, the form in the template does not render but also does not produce any errors. I can't figure out why since there is no error produced.