开发者

How would you make a dynamic formset in Django?

开发者 https://www.devze.com 2022-12-21 18:16 出处:网络
Here\'s the way I\'m doing it: {{ formset.management_form }} <table> {% for form in formset.forms %}

Here's the way I'm doing it:

{{ formset.management_form }}
<table>
    {% for form in formset.forms %}
        开发者_开发知识库{{ form }}
    {% endfor %}
</table>
<a href="javascript:void(0)" id="add_form">Add Form</a>   

And here's the JS:

var form_count = {{formset.total_form_count}};
$('#add_form').click(function() {
    form_count++;
    var form = '{{formset.empty_form|escapejs}}'.replace(/__prefix__/g, form_count);
    $('#forms').append(form)
    $('#id_form-TOTAL_FORMS').val(form_count);
});

What specifically bothers me is that I had to write that escapejs template tag myself. It just strips all newlines and escapes any single quotes so that it doesn't mess up my string. But what exactly did the Django makers expect us to do in this situation? And why do they have this TOTAL_FORMS hidden field, when they could have just used an array like <input name="my_form_field[0]" /> and then counted its length instead?


There are a few places in Django where "the reason why" is because that's how it was implemented for the Django admin app, and I believe this is one of them. Thus the answer is they expect you to implement your own javascript.

See this SO question Dynamically adding a form... for some more javascript ideas.

There are also two pluggable apps available, django-dynamic-formset and django-dinamyc-form which I hadn't seen until just now when looking up the first one.


This question is a bit old, but it took me a while to figure this out as well.

I suggest rendering formset.empty_form in your template as a hidden field, and referencing this field in your javascript.

Here's a complicated dynamic formset example from the django admin site: (but note that it has not been updated to use empty_form....)

[js] http://code.djangoproject.com/browser/django/trunk/django/contrib/admin/media/js/inlines.js

[html template] http://code.djangoproject.com/browser/django/trunk/django/contrib/admin/templates/admin/edit_inline/tabular.html


It's because formset have been created to work without javascript, using only the usual HTTP workflow.

Django is javascript agnostic.

If you want to add some javascript to the mix, you can use the dedicated jquery plugin.


in my case. i used the plugin django-dynamic-formset (https://code.google.com/p/django-dynamic-formset/wiki/Usage)

and modified the option "added" and worked good.

        $('#formset-table tbody tr').formset({
            prefix: '{{ formset.prefix }}',
            formCssClass: '{{ formset.prefix }}-inlineformset',
            added: function(obj_tr){ 
                var form = $(obj_tr).html().replace(/\-(\w+)\-(\w+)(fix__)\-/g, '-');
                $(obj_tr).html(form);

           },

this regular expression replace the string [prefix]-prefix peer '-'

maybe isn't the best solution, but worked.


There are some cases of possible XSS when using formset.empty_form as a string, replacing '__prefix__' to actual formset form index. My pluggable application converts formset.empty_form into Knockout.js template which is then cloned via custom Knockout.js bindings. Also Knockout.js automatically re-calculates form field id indexes, when newly added formset form is dynamically deleted before the whole form with inlineformsets was submitted. Here is the documentation:

https://django-jinja-knockout.readthedocs.org/en/latest/forms.html#dynamically-adding-new-related-formset-forms

Knockout.js binding also prevents XSS when loading custom fields with inline Javascript.

0

精彩评论

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