引导模态表单发布两次Django
我正在遵循django-bootstrap-modal-forms的说明,我发现在提交表单时,表单正在发布或提交两次。首先,该对象简单地创建了两次,我可以从管理员处看到这一点。现在,表单似乎正在创建对象,但也进入了它的验证状态,如果表单成功了,我显然不想要这样的状态,但它确实成功了。
有没有人经历过这种情况?除了我链接到的文档中概述的内容之外,我什么都没做,我找不出任何理由,为什么这应该提交两次。
以下是我的代码:
home.html
<a href="#" class="create-shipment dropdown-itemcreatenew" onclick="closeNav()">Shipment</a>
<div class="modal fade" tabindex="-1" role="dialog" id="modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
</div>
</div>
</div>
<script>
$(document).ready(function() {
$(".create-shipment").modalForm({
formURL: "{% url 'CreateShipmentView' %}"
});
});
</script>
views.py
class CreateShipmentView(BSModalCreateView):
template_name = 'create_shipment.html'
form_class = CreateShipmentForm
success_message = 'Success: Shipment Has Been Created!'
success_url = reverse_lazy('HomeView')
create_shiment.html(模式表单模板)
{% load crispy_forms_tags %}
<form method="post" action="">
{% csrf_token %}
<div class="modal-header">
<h5 class="modal-title">Create New Shipment</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
{{form|crispy}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="submit-btn btn btn-primary">Create</button>
</div>
</form>
forms.py
class CreateShipmentForm(BSModalForm):
class Meta:
model = Shipment
fields = ['Reference_Number', 'Ultimate_Consignee']
urls.py
url(r'^create_shipment/', views.CreateShipmentView.as_view(), name='CreateShipmentView'),
提交按钮上的事件侦听器
// Add click listener to the submitBtn
var ajaxSubmit = function (modalID, modalContent, modalForm, formURL, errorClass, submitBtn) {
$(submitBtn).on("click", function () {
// Check if form.is_valid() via ajax request when submitBtn is clicked
isFormValid(modalID, modalContent, modalForm, formURL, errorClass, submitBtn, submitForm);
});
};
// Check if form.is_valid() & either show errors or submit it
var isFormValid = function (modalID, modalContent, modalForm, formURL, errorClass, submitBtn, callback) {
$.ajax({
type: $(modalForm).attr("method"),
url: $(modalForm).attr("action"),
// Serialize form data
data: $(modalForm).serialize(),
success: function (response) {
if ($(response).find(errorClass).length > 0) {
// Form is not valid, update it with errors
$(modalID).find(modalContent).html(response);
$(modalForm).attr("action", formURL);
// Reinstantiate click listener on submitBtn
ajaxSubmit(modalID, modalContent, modalForm, formURL, errorClass, submitBtn);
} else {
// Form is valid, submit it
callback(modalForm);
}
}
});
};
解决方案
阅读套餐source code后,相信后台收到两个请求是正常的。
您的代码
$(document).ready(function() {
$(".create-shipment").modalForm({
formURL: "{% url 'CreateShipmentView' %}"
});
});
触发函数modalForm
以获取您的选项(formURL
),并将函数newForm
分配给单击事件。
然后在newForm
函数中调用函数addListeners
将点击事件绑定到模态中的提交按钮,事件调用如下:
isFormValid(modalID, modalContent, modalForm, formURL, errorClass, submitBtn, submitForm);
请注意,最后一个参数submitForm
指向以下函数
var submitForm = function(modalForm) {
$(modalForm).submit();
};
最后,在函数isFormValid
中,您在表单中输入的所有数据都将发布到您在action
属性中定义的url进行验证,如果没有错误,表单将提交到完全相同的url。
如果您挖洞进入这个包中的Python代码,事情就会变得有趣起来。BSModalForm
基于mixins.py
和here中的两个类,说明当请求不是由Ajax发出时,保存使用表单数据创建的实例,否则(如果Ajax调用请求)不保存该实例并返回它。这就是为什么它首先验证表单,但不应该保存它(请记住,第一个调用确实是通过使用jQuery中的Ajax调用发起的)。
您提到该表单正被保存两次-请尝试在save函数的开头添加一行,如下所示
print(request.is_ajax())
,然后检查输出。可能是调用未能作为Ajax调用发送。(如果是这种情况,请更新您的jQuery版本或使用其他方式(如axios)进行调用)
如果您不喜欢事情发生的方式,可以选择以下几个选项(麻省理工学院许可下的软件包):
更改
save
函数以验证实例,然后将其另存为普通的Django保存函数,但这涉及更改某些JS代码。让API端点使用json接收数据并进行通信,而不是每次都返回html代码(我猜这也是作者以当前方式编写JS的原因,因为这样会面临呈现问题)。因为目前提交表单后不需要执行任何其他操作,所以再返回实例就没有意义了。(不需要DRF,因为Django中内置了JsonResponse类,并且如果您只需要这一个端点)
直接使用bootstrap,因为这里的故事相当简单:页面上有一个模式,触发模式的按钮,模式中的表单,您可以提交它。您可能需要编写一些自己的JS来显示错误,但这仍然比更改现有包容易。
示例
# forms.py
from django import forms
# use django ModelForm for creating the form based on model
class CreateShipmentForm(forms.ModelForm):
class Meta:
model = Shipment
fields = ['Reference_Number', 'Ultimate_Consignee']
用于呈现表单(GET)和接收表单提交(POST)的视图
# views.py
from yourapp.forms import CreateShipmentForm
from django.shortcuts import render
def create_shipment_view(request):
# http POST request means that the form was submitted
if request.method == 'POST':
# create the form and map the data to CreateShipmentForm
shipment_form = CreateShipmentForm(request.POST)
# based on your design of the form/modal, validate the data passed into the form
if shipment_form.is_valid():
# create a new shipment object
new_shipment = shipment_form.save()
# form processing is finished now do something to alert user, for example redirect the user to the success page
return redirect('success')
# if the form is not valid, then shipment_form.errors contain all the errors
else:
# for all other accessing methods including GET
# create an empty form
shipment_form = CreateShipmentForm()
# if the request was POST, the form contains errors, if request was GET, it's an empty form
return render(request, 'path/to/template.html', {
'form': shipment_form
})
最后,在您的模板中,您可以像往常一样显示表单。如果您不知道或需要表单的某些其他功能,请继续使用易碎的表单。
如果要向用户显示错误,请选中模板中的if shipment_form.errors
并将其显示在模板中。
相关文章