Wil
Wil

Reputation: 5057

Adding fields to a Django form dynamically with JavaScript & JSONField

I have a model form in which I need to store an unknown number of helpers alongside a thing. The names can be serialised upon save, and that's not a problem. It's being able to clean and validate them upon submission.

The form looks like;

class ThingForm(forms.ModelForm):
    """
    Form for the Thing
    """
    owner = forms.CharField()
    helpers = forms.CharField()

    class Meta:
        model = Thing

    def save(self, *args, **kwargs):
        """
        Serialize helpers to JSON.
        """
        ...

And the model is using a JSONField to store the serialised helpers.

class Thing(models.Model):
    owner = models.CharField()
    helpers = JSONField()

I have JavaScript adding as many helpers as required with the same input name:

<input name="helpers" value="Fred" />
<input name="helpers" value="Joe" />

Which is returning a tuple of the helpers. The problem is that the if the form isn't valid - those names will be lost and the cleaning isn't working.

My first thought was to add to the form's constructor:

    def __init__(self, *args, **kwargs):
        super(ThingForm, self).__init__(*args, **kwargs)
        try:
            helpers = args[0].pop('helpers')
            for name in helpers:
                # Add a charfield, or something?
        except:
            pass

But I'm not really getting anywhere...

Upvotes: 3

Views: 1510

Answers (3)

msbrogli
msbrogli

Reputation: 493

We had a similar problem and found no ready solution. So we did ours (https://github.com/vialink/vlk-django-jsonfield).

Upvotes: 0

Wil
Wil

Reputation: 5057

Thanks to AdamKG for the answer to this. You can just use the list in your view again:

View:

if request.method == 'POST':
    helpers = request.POST.getlist('helpers')
    form = ThingForm(request.POST)
    if form.is_valid():
        form.save()
        return HttpResponseRedirect('/saved/')
else:
    helpers = None
    form = ThingForm()

return render_to_response('my_template.html',
    {'helpers': helpers, 'form': form},
    context_instance=RequestContext(request))

Template:

{% for field in form %}
    {% if field.name == 'helpers' %}
        {% for name in helpers %}
            <input name="helpers" value="{{ name }}" />
        {% endfor %}
    {% else %}
        {{ field }}
    {% endif %}
{% endfor %}

Upvotes: 1

AdamKG
AdamKG

Reputation: 14081

I think all you need to do is do something like this in your template:

{% if form.data %}{# eg, was invalid and this is a re-render w/ errors #}
{% for helper in form.data.helpers %}
<input type="hidden" name="helpers" value="{{ helper }}">
{% endfor %}
{% endif %}

Note that this will break if you start passing a prefix kwarg to your form - but so would your original code, fixing that is a separate issue :)

Upvotes: 0

Related Questions