Multiple django inlineformset_factory problem

56 views
Skip to first unread message

Farhan Khan

unread,
Oct 9, 2014, 2:28:45 PM10/9/14
to django...@googlegroups.com
Hi all,

I am writing a tool that implements NIST security controls and having trouble implementing inlineformset_factory, which I think is the solution to this problem.

Background: I have two models, one is called 'Controls' and the other is 'Implementation'. When the user goes to a page, the views.py should query several relevant controls as text (not as a Form) and then an Implementation form immediately afterwards. This will be repeated depending on the number of Controls are found.

So, lets suppose there are 20 controls, you should see a table with the following:

{% for control in controlset %}

Control Name: "This is the control name 1" -- Presumably this comes from: {{ control.name.value }}
Control Description: "This is the control description 1" -- Presumably this comes from: {{ control.description.value }}
Implementation Statement: [Input type=text name=1_implementation] -- Not sure how to display this
Implementation Status: [Input type=text name=1_status] -- Not sure how to display this

{% endfor %}

(This is pseudo-code, removed the HTML for visibility)

This frame should be repeated depending on the number of controls, it could be 5, 20 or 100, then a submit button. When the user submits the data, I want to capture this data into several 'Implementation' objects and save them in the database.

My failing code currently does this:

ControlImplementationSet = inlineformset_factory(Controls, Implementation)
allControls
= Controls.objects.get(pk=1)
controlset
= ControlImplementationSet(instance=allControls)

Even though I want multiple forms, I used the Controls.objects.get(pk=1) to specify a single control. When I send the variable controlset as a context to be displayed as:

{{ controlset }}

I oddly get 3 forms that look like autogenerations of the Implementation form with an extra "Delete" option. That makes no sense to me. I don't know understand why this is displayed. I want to display the queried controls, followed by an implementation form.

My questions are:
  1. Why do I get 3 "Implementation" forms, instead of just 1, when I did Controls.objects.get(pk=1), which should specify a single Control?
  2. How do I display multiple Implementation Forms for each Control that is returned?
  3. How do I only display certain elements of the Implementation form, not every field in the model as an HTML <input> field?
  4. How do I have my views.py interpret the submitted Implementation form data from the user?
And last but not least...is there a sample of this? Surely I am not the first one who has done this, and the he documentation is not making sense to me.
https://docs.djangoproject.com/en/1.7/topics/forms/modelforms/#inline-formsets

Please advise, this is day two, quite frustrated.

Thanks,
Farhan

Collin Anderson

unread,
Oct 9, 2014, 3:48:18 PM10/9/14
to django...@googlegroups.com
Ahh, yes, those docs assume you've also read the non-model formset docs:
https://docs.djangoproject.com/en/1.7/topics/forms/formsets/

Why do I get 3 "Implementation" forms, instead of just 1, when I did Controls.objects.get(pk=1), which should specify a single Control? 
It will show one form for each implementation already in the database, plus, by default, one "extra" blank form for adding an additional implementation for that control.

How do I display multiple Implementation Forms for each Control that is returned?
Formsets are for handling an arbitrary number of forms, and it sounds like you want _multiple_ _formsets_.

How do I only display certain elements of the Implementation form, not every field in the model as an HTML <input> field?

How do I have my views.py interpret the submitted Implementation form data from the user?
I think your case is pretty complicated. Does this seem right?

ControlImplementationSet = inlineformset_factory(Controls, Implementation, fields=['implementation', 'status'])

def the_view(request):
    controls
= Controls.objects.all()
    controlsets
= []
   
if request.method == 'POST':  # handling submitted data
        all_valid
= True
       
for control in controls:
            formset
= ControlImplementationSet(request.POST, instance=control, prefix='control_%s' % control.pk)
           
if not formset.is_valid():
                all_valid
= False
            controlsets
.append(formset)
       
if all_valid:
           
for formset in controlsets:
                formset
.save()
           
return redirect('/success!/')
   
else:  # displaying the forms the first time
       
for control in controls:
            formset
= ControlImplementationSet(instance=control, prefix='control_%s' % control.pk)
            controlsets
.append(formset)
   
return render(request, 'the_template.html', {'controlsets': controlsets})

Then, in your template:
{% for formset in controlsets %}

Control Name: {{ formset.instance.name }}
Control Description: {{ formset.instance.description }}

{% for form in formset %}  {# multiple forms per control #}
Implementation Statement: {{ form.implementation }}
Implementation Status: {{ form.status }}
{% endform %}

{% endfor %}

Reply all
Reply to author
Forward
0 new messages