开发者

Dynamically added form fields are removed in form.cleaned_data

开发者 https://www.devze.com 2023-01-27 01:09 出处:网络
I put some client-side Javascript in my template that allows a user to dynamically add fields to a form.My problem is that these fields are cleaned in form.cleaned_data, so I can\'t access them that w

I put some client-side Javascript in my template that allows a user to dynamically add fields to a form. My problem is that these fields are cleaned in form.cleaned_data, so I can't access them that way.

All the fields are accessible in request.POST, so I could just solve this problem with that, but I want to do this the "right way" and I think that the solution lies somewhere in using django forms rather than reading the request directly.

I tried overriding form.clean(), but it seems like the data is already gone by the time it gets there.

Other details: I am naming these fields fieldname_x, where x is a number. In request.POST, request.POST['fieldname'] is a list of a all th开发者_如何学编程e values, but form.cleaned_data contains only the last value of each list.


Do you know what type these fields are going to be beforehand? Are they just going to be simple text fields? I've done something similar to this, creating dynamic forms.

# make sure these exist by examining request.POST
custom_fields = ['fieldname_1', 'fieldname_2']

attrs = dict((field, forms.CharField(max_length=100, required=False)) 
             for field in custom_fields)
DynamicForm = type("DynamicForm", (YourBaseForm,), attrs)
submitted_form = DynamicForm(request.POST)

Your submitted form should now contain all the fields you require, along with their values. You might want to remove required=False, but that's up to you.

What this does, is perform a dynamic subclass of your base form, adding the attributes passed in as attrs to the class definition. So when you create an instance with post data, they should be mapped correctly.

Edit:

I read the question a little more closely. What you'll want to do is ensure that your dynamic input elements are named correctly, and the values map to those fieldnames once it reaches django. Otherwise, request.POST will not fill the form in correctly.

<input type='text' name='fieldname_1' value='value_for_field_1' /> 

etc


It is also possible to do this work in your form file, here is an excellent demonstration by Jacob Kaplan-Mosse for dynamic forms : http://jacobian.org/writing/dynamic-form-generation/ that applies quite well for this problem.

What is done is adding a methods to you form class that add the extra dynamic fields and then yields the information from the clean so that you can get it in your view.

class MyForm(forms.Form):
    text = forms.CharField(max_length=30)

    def __init__(self, *args, **kwargs):
        extra = kwargs.pop('extra')
        super(MyForm, self).__init__(*args, **kwargs)

        for i, question in enumerate(extra):
            self.fields['fieldname_%s' % i] = forms.CharField(label=question)

    def extra_fields(self):
        for name, value in self.cleaned_data.items():
            if name.startswith('fieldname_'):
                yield (self.fields[name].label, value)

And to call it from the view :

def doSomething(request, extra_fields):
    form = MyForm(request.POST or None, extra=extra_fields)
    if form.is_valid():
        for (question, answer) in form.extra_answers():
            save_answer(request, question, answer)
        return redirect("create_user_success")

return render_to_response("template/form.html", {'form': form})

Very neat, congrats to Jacob Kaplan-Moss


I'm doing this in the project I'm currently working on. You'll want to have a look at formsets. But be warned, it isn't pretty. You have to modify this stupid hidden field that stores to the form count, and you have to rename the inputs correctly.. which involves a lot of pointless string parsing. If they had used arrays, like PHP, there wouldn't be an issue, but they're hell bent on making my life miserable... rambles off

Edit: http://docs.djangoproject.com/en/dev/topics/forms/formsets/#empty-form they provide this which makes your life 5% less painful... you can just do a find and replace on prefix with the appropriate number.. but I think I had an issue where the empty form doesn't contain the proper default values if you initialize the form with post data, so I had to create a 2nd instance without post data to an actually empty empty_form, which is just retarded.

0

精彩评论

暂无评论...
验证码 换一张
取 消