0

I am trying to dynamically add field to a form in Django using JQuery. I have found several similar questions but the one that address the issue the best, I think its this one.

Although I understand most the logic, I can not make it work in my case. Moreover I am not sure why he is doing something in certain ways.

My code (according to the above link) looks like this:

View

def create_one(request):
    if request.method == 'POST':
        form_empty_layer = UploadEmptyLayerForm(request.POST, extra=request.POST.get('extra_field_count'))

        if form_empty_layer.is_valid():
            print "valid!"
    else:
        form = UploadEmptyLayerForm()
    return render(request, "template", { 'form_empty_layer': form_empty_layer })

Form

class UploadEmptyLayerForm(forms.Form):

    empty_layer_name = forms.CharField(max_length=255, required=True, label="Name of new Layer")

    extra_field_count = forms.CharField(widget=forms.HiddenInput())

    def __init__(self, *args, **kwargs):

        extra_fields = kwargs.pop('extra', 0)
        super(UploadEmptyLayerForm, self).__init__(*args, **kwargs)
        self.fields['extra_field_count'].initial = extra_fields

        for index in range(int(extra_fields)):
            # generate extra fields in the number specified via extra_fields
            self.fields['extra_field_{index}'.format(index=index)] = \
                forms.CharField()

Template

 <form id="empty-layer-uploader" method="post" enctype="multipart/form-data" action="{% url "layer_create" %}">
    <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
      {% for field in form_empty_layer.visible_fields %}
        {{ field|as_bootstrap }} </br>
      {% endfor %}
      <button type="button" id="add-another">add another</button> </br> </br>
      <button type="submit" id="empty-layer-button" class="btn btn-danger" name="emptylayerbtn">Upload</button>
  </form>

And the jquery:

form_count = $("[name=extra_field_count");
// get extra form count so we know what index to use for the next item.
$(document.body).on("click", "#add-another",function(e) {
  element = $('<input type="text"/>');
  element.attr('name', 'extra_field_' + form_count);
  $("#empty-layer-uploader").append(element);
  // build element and append it to our forms container

  form_count ++;

  $("[name=extra_field_count]").val(form_count);

  // increment form count so our view knows to populate
  // that many fields for validation
  })

As you might notice I have added a type attribute in the button element (type = button). Also its not clear to me what is happening in the first line of the jquery:

form_count = $("[name=extra_field_count");

Isn't suppose to set form_count = 0? If not, isn't like that a ']' is missing?

Nevertheless when I try to run this I get that:

 int() argument must be a string or a number, not 'NoneType'

The code never fetches the number of created input elements. If I set manually in the view the extra variable then the whole process starts working:

form_empty_layer = UploadEmptyLayerForm(request.POST, extra=3)

So I guess the question is why the value is not passed correctly from the template to the view.

PYTHON ERROR

  Traceback (most recent call last):
  File "/home/vagrant/.venvs/geonode/lib/python2.7/site-packages/django/core/handlers/base.py", line 112, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/vagrant/.venvs/geonode/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 22, in _wrapped_view
return view_func(request, *args, **kwargs)
 File "/home/vagrant/geonode/geonode/layers/views.py", line 885, in layer_create
form_empty_layer = UploadEmptyLayerForm(request.POST, extra=request.POST.get('extra_field_count'))
 File "/home/vagrant/geonode/geonode/layers/forms.py", line 324, in __init__
for index in range(int(extra_fields)):

TypeError: int() argument must be a string or a number, not 'NoneType'

EDIT

Using the recommendations of @Ian Price I have solved the error I was getting. But I still have issues when I try to fetch the values from the newly added fields. By adding two new fields and executing in my view:

data = form_empty_layer.cleaned_data
print data

I get:

{'empty_layer_name': u'4234', 'extra_field_1': u'', 'extra_field_0': u'', 'extra_field_count': u'5645', 'geom_type': u'POINT'}

So there is something really wrong with the architecture of the application. The keys: extra_field_1 and extra_field_2 should be populated with the values I added. Instead the extra_field_count gets the latest of the two values I added.

Community
  • 1
  • 1
user1919
  • 3,818
  • 17
  • 62
  • 97
  • You most definitely should be receiving both JS errors in your browser console, and Python errors in your terminal. Please share both. – rnevius Jun 26 '16 at 13:46
  • Thanks. I actually get nothing in the web developers tool. And I already mentioned the error I get in python. But I have edited the question with the complete error. – user1919 Jun 26 '16 at 13:50

1 Answers1

1

request.POST.get('extra_field_count') seems to be the culprit for that error. With the form field extra_field_count not having an extra field count, it has no value. However, the pointer to a value of None still exists, and so can be found in the init method of your form, even though it has a value of none.

Consider this example.

>>> mydict = {'a':None}
>>> print mydict.pop('a')
None

request.POST and kwargs are dictionaries just like mydict.

The easiest fix? Check for null values in the __init__ method of your form.

extra_fields = kwargs.pop('extra', 0)
if not extra_fields:
    extra_fields = 0
Ian Price
  • 7,416
  • 2
  • 23
  • 34
  • Thanks. This fixes the error. But I still can not make my form to work properly. It doesn't pass the validation test (form.is_valid). Any ideas why this could happen? – user1919 Jun 27 '16 at 07:17
  • I think I know what's going on. For the new fields I create I have set that they must be required (required=True). I think this is causing the error. Setting required=False actually passes the form validation. But still I need to find a way how to fetch the data from the newly generated field. Any help is highly appreciated! – user1919 Jun 27 '16 at 07:21
  • If I add two new fields, I can access in my view the last value of the new added field as print(extra_field_count) but how can I access the previous ones? – user1919 Jun 27 '16 at 07:38