Keith Keith - 1 month ago 12
Python Question

django modelformset_factory doesn't include actual forms

I've been trying to follow tutorials and other SO questions and have a

modelformset_factory
that's displaying a list of what looks like forms in the html, but it turns out they're not actual forms.

html that gets displayed:

<div ='container'>

<div class='row'><tr><th><label for="id_form-0-config_key">Config key:</label></th><td><input id="id_form-0-config_key" maxlength="63" name="form-0-config_key" type="text" value="ClientMustVerify" /></td></tr>
<tr><th><label for="id_form-0-config_value">Config value:</label></th><td><input id="id_form-0-config_value" maxlength="63" name="form-0-config_value" type="text" value="TRUE" /><input id="id_form-0-id" name="form-0-id" type="hidden" value="3" /></td></tr> <input type="submit" value="Update" /></div>

<div class='row'><tr><th><label for="id_form-1-config_key">Config key:</label></th><td><input id="id_form-1-config_key" maxlength="63" name="form-1-config_key" type="text" value="Auditing" /></td></tr>
<tr><th><label for="id_form-1-config_value">Config value:</label></th><td><input id="id_form-1-config_value" maxlength="63" name="form-1-config_value" type="text" value="FALSE" /><input id="id_form-1-id" name="form-1-id" type="hidden" value="4" /></td></tr> <input type="submit" value="Update" /></div>

<div>


notice there is no
form
tag anywhere. working backwards, here's the excerpt from the template:

<div ='container'>
{% for form in formset %}
<div class='row'>{{form}} <input type="submit" value="Update" /></div>
{% endfor %}
<div>


yes, I added the
submit
button manually hoping to get these to work, but of course if there isn't a
form
tag, then the
submit
button won't do anything.
views.py:

from limbo.models import serverConfig
from django.forms import modelformset_factory
from django.forms import formset_factory

def editServer(request):
result = serverConfig.objects.values()
myConfigs = [entry for entry in result]

finalFormSet = modelformset_factory(serverConfig, exclude=('id',), extra=0)
#other lines
return render(request, 'limboHtml/ServerConfiguration.html', {'formset': finalFormSet, 'SubmitMessage': '', 'CurrentConfigs': myConfigs})


forms.py:

class serverForm(ModelForm):
class Meta:
model = serverConfig
fields = ['config_key', 'config_value']
def __init__(self, *args, **kwargs):
super(serverForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if instance and instance.pk:
self.fields['config_key'].widget.attrs['readonly'] = True
self.fields['config_key'].widget.attrs['disabled'] = True


and models.py:

class serverConfig(models.Model):

config_key = models.CharField(max_length=63)
config_value = models.CharField(max_length=63)


I tried using
finalFormSet = formset_factory(serverForm, extra=0)
at one point, but then I just got no content in the html...

Answer

As described in the formset documention you must add the form tag manually. This is not very different from what you do when displaying a single form.

It appears that you are iterating through the formset and displayig them one by one. That means you must also add the management form

<form method="post" action="">
    {{ formset.management_form }}
    <div ='container'>
        {% for form in formset %}
            <div class='row'>{{form}} <input type="submit" value="Update" /></div>
        {% endfor %}
    <div>
</form>

Or you will get errors about a missing or misconfigured management form.