清理后的数据仅显示最后一个表单集数据

时间:2019-04-05 13:18:32

标签: django django-forms cleaned-data

我有一个django项目,我在其中使用django admin创建仪表板,并使用请求库向API发出请求。我还使用表单集动态创建多个表单。当我发出发布请求并使用ipdb观察数据时,我发现前n-1个表单集中的数据不在清理的数据中。仅将最后一种形式的数据添加到json中。我如何使所有表单中的数据都显示在json中。这是我的代码,

#forms.py
class CampaignForm(forms.Form):
    consumer = forms.CharField(label="Consumer", max_length=200)
    startDate = forms.DateTimeField(label="Start Date",
        input_formats=['%d/%m/%Y %H:%M'])
    endDate = forms.DateTimeField(label="End Date",
        input_formats=['%d/%m/%Y %H:%M'])
    referreeCredits = forms.IntegerField(label="Referree Credits")
    referrerCredits = forms.IntegerField(label="Referrer Credits")
    maxReferreeCredits = forms.IntegerField(label="Max Referree Credits")
    maxReferrerCredits = forms.IntegerField(label="Max Referrer Credits")
    message = forms.CharField(label="Message", max_length=200)
    kramerTemplateId = forms.CharField(label="Kramer Template ID", max_length=200)
    paymentMode = forms.ChoiceField(label="Payment Mode", choices=[("PAYTM","PAYTM")])

class RuleForm(forms.Form):
    eventName = forms.CharField(label="Event Name", max_length=200)
    operator = forms.ChoiceField(label="Operator", choices=[("EQUAL","EQUAL"), ("EVERY","EVERY")])
    value = forms.IntegerField(label="Value")

class MilestoneRulesForm(forms.Form):
    moperator = forms.ChoiceField(label="Operator", choices=[("EQUAL","EQUAL"), ("EVERY","EVERY")])
    mvalue = forms.IntegerField(label="Value")
    mreferrerCredits = forms.IntegerField(label="Referrer Credits")

HTML模板:

#html
    {% block content %}
        <div class="form_div" style="width:60%;">
            <h2>Campaign Form</h2>
            <form method="POST">
                {% csrf_token %}
                {% for field in form.visible_fields %}
                    <div class="form-group">
                        {{ field.label_tag }}
                        {% render_field field class="form-control" %}
                        {% if field.help_text %}
                            <small class="form-text text-muted">{{ field.help_text }}</small>
                        {% endif %}
                    </div>
                {% endfor %}            
                <div style="display: flex; justify-content: space-between; width: 280px;">
                <h3>Rules</h3><button type="button" id="generate-rule" class="btn btn-primary">+</button>
                </div>
                <div class="parent">
                <div>
                {{ rule_formset.management_form }}
                {% for ruleForm in rule_formset %}
                    {{ ruleForm.eventName.label}}
                    {{ ruleForm.eventName }}
                    {{ ruleForm.operator.label }}
                    {{ ruleForm.operator }}
                    {{ ruleForm.value.label }}
                    {{ ruleForm.value }}
                    <input type="button"  class="btn btn-warn" style="background: red;" value="-">
                {% endfor %}
                </div>
                </div>
                 <div style="display: flex; justify-content: space-between; width: 280px;">
                <h3>Milestone Rules</h3><button  type="button" id="generate-milestone-rule" class="btn btn-primary">+</button>
                </div>
                <div class="milestone-parent">
                <div>
                {{ milestone_formset.management_form }}
                {% for milestoneForm in milestone_formset %}
                    {{ milestoneForm.moperator.label }}
                    {{ milestoneForm.moperator }}
                    {{ milestoneForm.mvalue.label }}
                    {{ milestoneForm.mvalue }}
                    {{ milestoneForm.mreferrerCredits.label }}
                    {{ milestoneForm.mreferrerCredits }}
                    <input type="button"  class="btn btn-warn" style="background: red;" value="-">
                {% endfor %}
                </div>
                </div>
                <div>
                <input type="submit" value="Post">
                </div>
            </form>
        </div>

        <script>
            $(function () {
                $("#id_startDate").datetimepicker({
                format: 'd/m/Y H:i',
                });
                $("#id_endDate").datetimepicker({
                format: 'd/m/Y H:i',
                });
            });
        </script>

        <script type='text/javascript'>

            const ruleform = `
            <div>
                <input type="hidden" name="form-TOTAL_FORMS" value="1" id="id_form-TOTAL_FORMS">
                <input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS">
                <input type="hidden" name="form-MIN_NUM_FORMS" value="0" id="id_form-MIN_NUM_FORMS">
                <input type="hidden" name="form-MAX_NUM_FORMS" value="1000" id="id_form-MAX_NUM_FORMS">

                    Event Name
                    <input type="text" name="form-0-eventName" maxlength="200" id="id_form-0-eventName">
                    Operator
                    <select name="form-0-operator" id="id_form-0-operator">
                    <option value="EQUAL">EQUAL</option>

                    <option value="EVERY">EVERY</option>

                    </select>
                    Value
                    <input type="number" name="form-0-value" id="id_form-0-value">
                    <input type="button" class="btn btn-warn" style="background: red;" value="-">

                </div>
                `
            const milestoneform = `
            <div>
                <input type="hidden" name="form-TOTAL_FORMS" value="1" id="id_form-TOTAL_FORMS">
                <input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS">
                <input type="hidden" name="form-MIN_NUM_FORMS" value="0" id="id_form-MIN_NUM_FORMS">
                <input type="hidden" name="form-MAX_NUM_FORMS" value="1000" id="id_form-MAX_NUM_FORMS">

                    Operator
                    <select name="form-0-operator" id="id_form-0-operator">
                    <option value="EQUAL">EQUAL</option>

                    <option value="EVERY">EVERY</option>

                    </select>
                    Value
                    <input type="number" name="form-0-value" id="id_form-0-value">
                    Referrer Credits
                    <input type="number" name="form-0-referrerCredits" id="id_form-0-referrerCredits">
                    <input type="button" class="btn btn-warn" style="background: red;" value="-">

                </div>
            `
            $("#generate-rule").on('click', function(e){
                $(".parent").append(ruleform)
            })
            $("#generate-milestone-rule").on('click', function(e){
                $(".milestone-parent").append(milestoneform)        
            })
            $(".parent").on("click", (e) => {
                return e.target.classList.contains('btn-warn') && e.target.parentNode.remove()
            })

            $(".milestone-parent").on("click", (e) => {
                return e.target.classList.contains('btn-warn') && e.target.parentNode.remove()
            })
        </script>
    {% endblock %}

views.py:

def campaign_add(self, request):
        form = CampaignForm()
        RuleFormSet = formset_factory(RuleForm)
        MilestoneFormSet = formset_factory(MilestoneRulesForm)
        if request.method == 'POST':
            # import ipdb; ipdb.set_trace()
            form = CampaignForm(request.POST)
            rule_formset = RuleFormSet(request.POST)
            milestone_formset = MilestoneFormSet(request.POST)
            if form.is_valid() and rule_formset.is_valid() and milestone_formset.is_valid():
                import ipdb; ipdb.set_trace()
                # <QueryDict: {'csrfmiddlewaretoken': ['q9Ox6KtEWUxIFXm305KhGRlHcliXtIgc6AjjqjkhG7p791tKvILMXZh8yZdWJWSW'], 'consumer': ['FILING'], 'startDate': ['05/04/2019 16:28'], 'endDate': ['06/04/2019 16:28'], 'referreeCredits': ['50'], 'referrerCredits': ['50'], 'maxReferreeCredits': ['50'], 'maxReferrerCredits': ['50'], 'message': ['Hello'], 'kramerTemplateId': ['kt01'], 'paymentMode': ['PAYTM'], 'form-TOTAL_FORMS': ['1', '1'], 'form-INITIAL_FORMS': ['0', '0'], 'form-MIN_NUM_FORMS': ['0', '0'], 'form-MAX_NUM_FORMS': ['1000', '1000'], 'form-0-eventName': ['string'], 'form-0-operator': ['EQUAL'], 'form-0-value': ['0'], 'form-0-moperator': ['EQUAL'], 'form-0-mvalue': ['0'], 'form-0-mreferrerCredits': ['50']}>
                dat = {}
                dat["consumer"] = form.cleaned_data["consumer"]
                dat["startDate"] = self.datetime_to_epoch(form.cleaned_data["startDate"])
                dat["endDate"] = self.datetime_to_epoch(form.cleaned_data["endDate"])
                dat["referreeCredits"] = form.cleaned_data["referreeCredits"]
                dat["referrerCredits"] = form.cleaned_data["referrerCredits"]
                dat["maxReferreeCredits"] = form.cleaned_data["maxReferreeCredits"]
                dat["maxReferrerCredits"] = form.cleaned_data["maxReferrerCredits"]
                dat["message"] = form.cleaned_data["message"]
                dat["kramerTemplateId"] = form.cleaned_data["kramerTemplateId"]
                dat["paymentMode"] = form.cleaned_data["paymentMode"]
                arrRules = rule_formset.cleaned_data
                arrMilestoneRules = milestone_formset.cleaned_data
                dat["eventRules"] = arrRules
                dat["milestoneRules"] = arrMilestoneRules
                print(dat)
                res = requests.post("https://example.com", data=json.dumps(dat), headers={'content-type': 'application/json'})
                if res.status_code == 201 or res.status_code == 200:
                    messages.success(request, 'Success!')
                    return redirect("admin:campaign-pg1")
                else:
                    messages.error(request, 'Submission Failed.')
        else:
            rule_formset = RuleFormSet()
            milestone_formset = MilestoneFormSet()
            return TemplateResponse(request, "admin/campaign_add.html", {"form":form, "rule_formset": rule_formset, "milestone_formset": milestone_formset})

request.POST中的数据:

<QueryDict: {'csrfmiddlewaretoken': ['LV5T8pd2DCileU9XFAdPwR23zbVn3sO8rmAFsY4FnPaKIYgEadekNZYuVPQmjGqS'], 'consumer': ['sx'], 'startDate': ['06/04/2019 17:40'], 'endDate': ['05/04/2019 19:00'], 'referreeCredits': ['23'], 'referrerCredits': ['22'], 'maxReferreeCredits': ['33'], 'maxReferrerCredits': ['1'], 'message': ['sdsd'], 'kramerTemplateId': ['kt01'], 'paymentMode': ['PAYTM'], 'form-TOTAL_FORMS': ['1', '1', '1'], 'form-INITIAL_FORMS': ['0', '0', '0'], 'form-MIN_NUM_FORMS': ['0', '0', '0'], 'form-MAX_NUM_FORMS': ['1000', '1000', '1000'], 'form-0-eventName': ['string', 'string2'], 'form-0-operator': ['EQUAL', 'EVERY'], 'form-0-value': ['3', '0'], 'form-0-moperator': ['EQUAL'], 'form-0-mvalue': ['3'], 'form-0-mreferrerCredits': ['4']}>

已清除数据中的数据:

{'consumer': 'sx', 'startDate': 1554552600.0, 'endDate': 1554471000.0, 'referreeCredits': 23, 'referrerCredits': 22, 'maxReferreeCredits': 33, 'maxReferrerCredits': 1, 'message': 'sdsd', 'kramerTemplateId': 'kt01', 'paymentMode': 'PAYTM', 'eventRules': [{'eventName': 'string2', 'operator': 'EVERY', 'value': 0}], 'milestoneRules': [{'moperator': 'EQUAL', 'mvalue': 3, 'mreferrerCredits': 4}]}

注意:eventRules中应该有来自两个字典(两种形式)的数据。仅显示一本字典。

为什么会这样?我该怎么办?

编辑1: 这是我在实现@pedro的答案后得到的request.POST

<QueryDict: {'csrfmiddlewaretoken': ['TqrjQp6mpuKaCRMcJtAq2ihxiLLtaEFrzRW5aYXZ9HCz6VTTe6BVjqdYEpGsqShb'], 'consumer': ['FILING'], 'startDate': ['05/04/2019 16:28'], 'endDate': ['06/04/2019 16:28'], 'referreeCredits': ['50'], 'referrerCredits': ['50'], 'maxReferreeCredits': ['50'], 'maxReferrerCredits': ['50'], 'message': ['Hello'], 'kramerTemplateId': ['kt01'], 'paymentMode': ['PAYTM'], 'form-TOTAL_FORMS': ['1', '1'], 'form-INITIAL_FORMS': ['0', '0'], 'form-MIN_NUM_FORMS': ['0', '0'], 'form-MAX_NUM_FORMS': ['1000', '1000'], 'form-0-eventName': ['string'], 'form-0-operator': ['EQUAL'], 'form-0-value': ['0'], 'form-{n}-eventName': ['string2'], 'form-{n}-operator': ['EVERY', 'EVERY'], 'form-{n}-value': ['1', '1'], 'form-0-moperator': ['EQUAL'], 'form-0-mvalue': ['1'], 'form-0-mreferrerCredits': ['50'], 'form-{n}-mReferrerCredits': ['20']}>

JavaScript错误

$("#generate-rule").on('click', function(e){
            var n = $("#id_form-TOTAL_FORMS").value; // current number of forms;
            var new_form = ruleform.replace(/{n}/g, n); // replace all {n} by the new form number
            $(".parent").append(new_form);
            $("#id_form-TOTAL_FORMS").value = parseInt(n) + 1; // update the total forms number
            console.log(n);
        })

$(“#id_form-TOTAL_FORMS”)。value返回未定义

Edit2: 我现在收到此错误-

Internal Server Error: /admin/campaign/add
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 126, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 124, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/utils/decorators.py", line 142, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/sites.py", line 223, in inner
    return view(request, *args, **kwargs)
  File "/Users/mohnishmallya/Desktop/Projects/campaign_dashboard/Referralapp/refapp/admin.py", line 50, in campaign_add
    if form.is_valid() and rule_formset.is_valid() and milestone_formset.is_valid():
  File "/usr/local/lib/python3.7/site-packages/django/forms/formsets.py", line 301, in is_valid
    self.errors
  File "/usr/local/lib/python3.7/site-packages/django/forms/formsets.py", line 281, in errors
    self.full_clean()
  File "/usr/local/lib/python3.7/site-packages/django/forms/formsets.py", line 322, in full_clean
    for i in range(0, self.total_form_count()):
  File "/usr/local/lib/python3.7/site-packages/django/forms/formsets.py", line 110, in total_form_count
    return min(self.management_form.cleaned_data[TOTAL_FORM_COUNT], self.absolute_max)
  File "/usr/local/lib/python3.7/site-packages/django/utils/functional.py", line 37, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/usr/local/lib/python3.7/site-packages/django/forms/formsets.py", line 92, in management_form
    code='missing_management_form',
django.core.exceptions.ValidationError: ['ManagementForm data is missing or has been tampered with']

在我看来这行-
如果form.is_valid()和rule_formset.is_valid()和Milestone_formset.is_valid():

我也略微更改了html模板代码

<div style="display: flex; justify-content: space-between; width: 280px;">
                <h3>Rules</h3>
                <button type="button" id="generate-rule" class="btn btn-primary">+</button>
            </div>
            <div class="parent">
            <div>
            {{ rule_formset.management_form }}
            {% for ruleForm in rule_formset %}
                {{ ruleForm }}
                <input type="button"  class="btn btn-warn" style="background: red;" value="-">
            {% endfor %}
            </div>
            </div>
             <div style="display: flex; justify-content: space-between; width: 280px;">
                <h3>Milestone Rules</h3>
                <button  type="button" id="generate-milestone-rule" class="btn btn-primary">+</button>
            </div>
            <div class="milestone-parent">
            <div>
            {{ milestone_formset.management_form }}
            {% for milestoneForm in milestone_formset %}
                {{ milestoneForm }}
                <input type="button"  class="btn btn-warn" style="background: red;" value="-">
            {% endfor %}
            </div>
            </div>

1 个答案:

答案 0 :(得分:-1)

问题出在您的javascript上,您应仅使用以下每种输入之一:

<input type="hidden" name="form-TOTAL_FORMS" value="1" id="id_form-TOTAL_FORMS">
<input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS">
<input type="hidden" name="form-MIN_NUM_FORMS" value="0" id="id_form-MIN_NUM_FORMS">
<input type="hidden" name="form-MAX_NUM_FORMS" value="1000" id="id_form-MAX_NUM_FORMS">

但是您正在将它们复制到JavaScript变量ruleformmilestoneform中。当您添加新表单时,必须更新输入form-TOTAL_FORMS的值,以下是ruleform的示例,您必须对milestoneform做同样的事情:

const ruleform = `
<div>
  Event Name
  <input type="text" name="form-{n}-eventName" maxlength="200" id="id_form-{n}-eventName">

  Operator
  <select name="form-{n}-operator" id="id_form-{n}-operator">
    <option value="EQUAL">EQUAL</option>
    <option value="EVERY">EVERY</option>
  </select>

  Value
  <input type="number" name="form-{n}-value" id="id_form-{n}-value">
  <input type="button" class="btn btn-warn" style="background: red;" value="-">
</div>
`

$("#generate-rule").on('click', function(e){
    var n = $("#id_form-TOTAL_FORMS").val(); // current number of forms;
    var new_form = ruleform.replace(/{n}/g, n); // replace all {n} by the new form number
    $(".parent").append(new_form);
    $("#id_form-TOTAL_FORMS").val(parseInt(n) + 1); // update the total forms number

})

在处理表单集时,所有表单都需要具有不同的编号,这就是为什么我在0中将{n}替换为ruleform的原因。我不确定是否错过了什么,但是希望这会让您对需要做的事情有所了解。