【问题标题】:Django: Multiple formsets within a formDjango:一个表单中的多个表单集
【发布时间】:2015-03-26 18:25:03
【问题描述】:

我正在处理一些 Django 表单,这些表单的代码库是从其他人那里继承的,这很好,但会增加混乱。

我正在尝试向表单添加第二个表单集。添加第二个表单集时,两个表单集都出现在页面上,但后端似乎不包含任何表单。这是我的代码示例(我添加的可能比推荐的要多,但我不想错过重要的东西):

view.py:

class Thing(StaffRequiredMixin, DetailView):
model = models.Thing

def post(self, request, *args, **kwargs):

    ...

    context = self.get_context_data(**kwargs)

    dispatch = {
        "thing_form": self.handle_thing_form,
        ...
    }

    return dispatch[self.request.POST.get("form_name")](context)

...

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

    context = super(Thing, self).get_context_data(*args, **kwargs)
    thing = self.model.objects.get(pk=self.kwargs["pk"])
    context["thing"] = thing

    to_handle = self.request.POST.get("form_name")

    if to_handle == "thing_form":
        context["thing_form"] = forms.Thing(
                   self.request.POST, 
                   instance=thing)

        context["formset1"] = forms.FormSet1(
                   self.request.POST,
                   queryset=models.Model1.objects.filter(thing=self.object),
                   prefix="thing1")

        context["formset2"] = forms.FormSet2(
                   self.request.POST, 
                   queryset=models.Model2.objects.filter(thing=self.object),
                   prefix="thing2")
    else:
        context["thing_form"] = forms.Thing(
                   instance=thing, 
                   user=self.request.user)

        context["formset1"] = forms.FormSet1(
                   queryset=models.Model1.objects.filter(thing=self.object),
                   prefix="stuff1")

        context["formset2"] = forms.FormSet2(
                   queryset=models.Model2.objects.filter(thing=self.object),
                   prefix="stuff2")

    # Other to_handle stuff
    ...

    return context

def handle_thing_form(self, context):

    form = context['thing_form']
    formset1 = context['formset1']
    formset2 = context['formset2']

    if form.is_valid() and formset1.is_valid() and formset2.is_valid():

        # Do some form logic
        ...

        form.save()

        # Formset stuff:
        # here, the formsets contain no forms
        changed_1 = [f for f in formset1 if f.has_changed()]
        changed_2 = [f for f in formset2 if f.has_changed()]

        for a_form in changed_1:

            #Do some formset logic
            ...

            a_form.save()

        for a_form in changed_2:
            #similar to 1

        return HttpResponseRedirect(self.get_next_url())

    return self.render_to_response(context)

forms.py:

class Form1(ModelForm):

    class Meta:
        model = models.Model1
        fields = ("field1", "field2", ...)

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

        super(Form1, self).__init__(*args, **kwargs)

        # Some readonly widget stuff etc
        ...


class Form2(ModelForm):

    #Same idea as Form1
    ...


FormSet1 = modelformset_factory(models.Model1, form=Form1, extra=0)
FormSet2 = modelformset_factory(models.Model2, form=Form2, extra=0)

模板:

<form id="thing-form" method="post">
    <input type="hidden" name="form_name" value="thing_form" />

    {% for field in thing_form.visible_fields %}

        {{ field }}
        ...

    {% endfor %}


    <a id="add-form1">Add</a>

    {{formset1.management_form}}
    <div id="formset1-div">

        {% for form in formset1.forms %}

            {{form.id}}
            {% for field in form.visible_fields %}

                <div class="controls">
                    {{field}}
                </div>

            {% endfor %}
        {% endfor %}
    </div>

    <div id="empty-form1>

        {% for field in formset1.empty_form.visible_fields %}
            <div class="controls">
                {{field}}
            </div>
        {% endfor %}
    </div>

    {{formset2.management_form}}
    <div id="formset2-div">

        {# same idea as above #}
        ...

    </div>

    <button type="submit">Update</button>
</form>

javascript:

$(document).ready(function(){

    $('#add-form1').click(function() {
        $('#formset1-div').prepend($('#empty_form1').html().replace(/__prefix__/g, 'thing1'));
        $('#id_form-TOTAL_FORMS').val(parseInt('thing1') + 1);
    });

    if ($("#formset1-div input").length === 0){
        $("#add-form1").trigger("click");
    }

    // Similar button stuff for formset2
    ...

})

无论如何,我在这里添加了很多,但我这样做是因为我不确定我哪里出错了,或者即使我尝试做的事情是可能的。

【问题讨论】:

    标签: django formset


    【解决方案1】:

    哇,我太笨了。 javascript 部分应该是这样的:

    $(document).ready(function(){
    
        $('#add-form1').click(function() {
            var thing1_index = $('#id_thing1-TOTAL_FORMS').val();
            $('#formset1-div').prepend($('#empty_form1').html().replace(/__prefix__/g, thing1_index));
            $('#id_thing1-TOTAL_FORMS').val(parseInt(thing1_index) + 1);
        });
    
        if ($("#formset1-div input").length === 0){
            $("#add-form1").trigger("click");
        }
    
        // Similar button stuff for formset2
        ...
    
    })
    

    不知道我是如何错过明显的parseInt('thing1') 没有意义。

    无论如何,它现在可以工作了。也许查看多个表单集的人会在这里找到有用的东西¯\_(ツ)_/¯

    【讨论】:

    • 不,你不傻,是 Django 的模板不适合复杂的 Web UI。和你一样,我发现模板很快变得太脆弱而无法维护。多个嵌套的表单集最终将我带到了 AngularJS,使用 Django 和 Django REST 框架作为后端。我发现这个组合效果很好。只是我的 2 美分,很高兴你知道了。
    猜你喜欢
    • 1970-01-01
    • 2010-09-22
    • 1970-01-01
    • 2019-09-02
    • 1970-01-01
    • 2012-09-16
    • 2016-03-22
    • 2012-07-05
    • 2019-04-23
    相关资源
    最近更新 更多