'ManagementForm data is missing or has been tampered with' 通过 XHR 提交表单时

'ManagementForm data is missing or has been tampered with' when submitting a form via XHR

我希望用户能够从现有的选项列表中select。但是,如果该选项不在数据库中已有的选项中,他们需要能够添加一个新项目,同时保留在主窗体上,因为在添加新项目之后,他们需要能够保存主窗体

我使用的是 JQuery 库 select2,它允许 tags:True 选项,如果不存在,用户可以将新项目添加到列表中。尽管如此,Django 会验证该字段,如果它发现一个不在数据库中的项目,则会引发错误。我最初的计划是在视图中捕获新值,然后(首先使用 commit=False 保存表单),如果它不在数据库中,则保存它。但是,如果不强制 Django 不验证该字段,这是不可行的,而我还没有做到这一点。

我目前正在研究的另一个选项是添加一个包含子表单的模式弹出窗口。当然,我想避免在另一个页面中打开子表单,这可以工作,但对用户来说非常不友好。

models.py:

class Venue(models.Model):
    venue_name = models.CharField(max_length=30)

class performanceOfCompositionNoDb(models.Model):

    venue = models.ForeignKey(Venue, on_delete=models.SET_NULL, null=True, blank=True)

forms.py:

class VenueForm(forms.ModelForm):
    class Meta:
        model = Venue
        fields = ['venue_name']

views.py:

def composition_edit_view(request, id=id):
    form_composition = CompositionForm(request.POST or None, instance=obj)
    form_venue = VenueForm(request.POST or None)

    if request.method == "POST" and form_composition.is_valid():
    form_composition.save()

    context = {

        'form_composition': form_composition,
        'form_venue': form_venue
[...]

def venue_add_view(request):

    form_venue = VenueForm(request.POST or None)

    if form_venue.is_valid():
        form_venue.save()

    context = {
        'form_venue': form_venue,
    }

    return render(request, "venue-add.html", context)

我的template.html:

{% include '../venue-add.html'%}
<form id="compositionForm" action='.' enctype="multipart/form-data" method='POST'>

{{form_composition}}

<p><a href="javascript:void(0)" data-open="addvenueModal">Add new venue</a></p>

<input class="button" type='submit' id='save' value='Save' />

</form>

地点-add.html:

<div class="reveal" id="addvenueModal" data-reveal>
<form action='.' enctype="multipart/form-data" method='POST'>
  {% csrf_token %}
  <div class="grid-container">
    <div class="grid-x grid-padding-x">

    {{ form_venue }}

</div>
    <input class="button" type='submit' value='Save' />

    </div>
</form>

</div>

我希望在单击 'Add new venue' 按钮时打开场地添加表单,这发生了。打开模式并输入新文本后,我单击模式的 'submit' 按钮。那时我收到“验证错误 - ['ManagementForm data is missing or has been tampered with']”。我在主模板中有其他表单集,如果我不添加新场地,它都可以正常工作。

我该如何解决这个问题?此外,如果有使用 select2 库并以更动态的方式添加新场所的方法,请告诉我!谢谢。

使用 XHR 进行测试

使用 XHR 在响应中给出相同的 ['ManagementForm data is missing or has been tampered with'] 错误:

<div class="reveal" id="addVenue" data-reveal>
<form id="addVenueForm" action='.' onsubmit="addVenue(this); return false;" enctype="multipart/form-data" method='POST'>
  {% csrf_token %}
  <div class="grid-container">
    <div class="grid-x grid-padding-x">

    {{ form_venue }}

</div>
    <input class="button" type='submit' value='Save' />

    </div>
</form>

<script type="text/javascript">   "use strict";

function addVenue (oFormElement) {

var oReq = new XMLHttpRequest();
var data = new FormData(oFormElement)

oReq.onload = {}
oReq.onreadystatechange = function() {
    if (oReq.readyState == XMLHttpRequest.DONE) {
    var result = oReq.responseText;}
}

oReq.open("post", oFormElement.action, true);
oReq.send(data);

} </script>

正如我所说,我 在我启动此模态的主窗体中有窗体集(工作正常)。尽管此模式不包含任何表单集,但它是一个简单的单字段表单,具有自己的 csrf 令牌。

编辑 2

好的,经过进一步调查,我发现错误源于

return render(request, "compositions/composition_edit.html", context)

在view.py。换句话说,当我在模式中点击 'submit' 时,出于某种原因,主窗体的 'submit' 也会启动,从而产生问题。我怎样才能隔离模态的 'submit' 并让主窗体的 'submit' 不被启动,除非明确点击?

我不得不将模态表单的 action 更改为我在 urls.py (action='/venue-add/') 中为该表单映射的地址。那解决了问题。

现在,无论我destroy/empty/repopulate select2() 下拉列表多少次,除非我刷新页面,否则新添加的项目不会显示在主窗体中。我认为这与以下事实有关:场地下拉列表的数据是由视图在加载主窗体时发送的,并且无论在页面之后对数据库进行了哪些更新,上下文都保持不变加载中。

出于上述原因,我正在调查在我自己的应用程序上使用 API 并通过 AJAX 调用获取和 POST 数据,这仍然给我带来问题。不过,我正在为此打开另一个问题。