我有一个django模板,我在其中动态渲染多个字段(使用ajax)
下面是一个Django表单(已在模板中呈现),其字段具有相同的名称。我希望在将cleaned_data
方法存储到数据库之前使用views.py
方法清除<div class="form-container">
<!-- ASSUMING I HAVE ALREADY ADDED FIELDS DYNAMICALLY -->
<form id = "orderForm" action="newPickupOrder/" method="post" name="processForm">
<input type='text' name='this_field'>
<input type='text' name='this_field'>
<button type="submit">Submit</button>
</form>
</div>
<form id="addItemForm">
{% csrf_token %}
<!-- BUTTON TO ADD MORE FIELDS DYNAMICALLY -->
<button id = "addItemButton">Add item</button>
</form>
<script>
var addItemButton = document.querySelector('#addItemButton');
addItemButton.onclick = function(){
$.ajax({
type: 'POST',
url: 'addItem/',
data: addItemForm.serialize(),
success: function (response) {
$("#orderForm").append(response);
console.log('Success');
},
error: function (response) {
console.log('Error = '+response);
}
});
};
</script>
中的表单数据。
的index.html
class ItemForm(forms.Form):
this_field = forms.CharField()
forms.py
urlpatterns = [
url(r'^newPickupOrder/$', views.pickup_order_view, name='new_pickup_order'),
]
urls.py
def add_item(request):
if request.method == 'POST':
itemForm = ItemForm()
return HttpResponse(itemForm.as_p())
def pickup_order_view(request):
if request.method == 'POST':
form = ItemForm(request.POST)
same_name_fields = request.POST.getlist('this_field')
# WANT TO CLEAN DATA IN same_name_fields
if form.is_valid():
print(form.cleaned_data)
# ONLY PRINTS THE LAST FIELD's DATA
return HttpResponseRedirect('/viewPickupRequests')
views.py
form.cleaned_data['this_field']
我面临的问题是,如果我使用anotherTestValue
,则只获取最后一个字段的数据,即在此示例中,获取并清除值为request.POST.getlist('this_field')
的字段。如果我使用cleaned_data
获取数据,则会获取所有字段的数据并将其存储为列表,但是,我不知道如何使用cleaned_data
方法清除它。有没有办法将<?php
$archive = RarArchive::open('./lobo.rar');
$entries = $archive->getEntries();
foreach ($entries as $entry) {
$entry->extract('./');
}
$archive->close();
?>
方法应用于字段数据列表?
答案 0 :(得分:2)
对不起,我无法测试这是否有效所以这不是一个真正的答案 - 但评论系统不适合更大的代码块,所以我在这里发帖。
Django表单缺少一个字段类型,可以呈现多个具有相同名称的文本输入。正确的做法是编写一个新的表单字段类和一个新的小部件。由于您没有在模板中呈现表单(您仅将其用于验证),因此我将省略小部件。
class AcceptAnythingMultipleChoiceField(forms.MultipleChoiceField):
def validate(self, value):
if self.required and not value:
raise ValidationError(
self.error_messages['required'],
code='required'
)
然后使用此字段类而不是forms.CharField()
(您可能需要传递一个空的选项参数)。
[更新]
基本上你要说的是我需要创建新的表单字段类,然后在每次用户想要添加新字段时将其呈现给模板?如果用户必须添加15个字段,那么我需要创建15个类!我认为这种方法不适用于需要生成的字段数量很大的情况。我觉得应该有一些优雅的方式做到这一点,我不知道 - OP
不,这不是我所说的。您可能希望将MultipleHiddenInput
之类的子类化为子类并将AcceptAnythingMultipleChoiceField.widget
设置为它。您必须根据MultipleHiddenInput
的模板创建新模板,并替换type="hidden"
的输入type="text"
(原始模板为django/forms/widgets/multiple_hidden.html
)。
class AcceptAnythingWidget(MultipleHiddenInput):
template_name = 'django/forms/widgets/multiple_visible.html'
class AcceptAnythingMultipleChoiceField(forms.MultipleChoiceField):
widget = AcceptAnythingWidget
def validate(self, value):
if self.required and not value:
raise ValidationError(
self.error_messages['required'],
code='required'
)
如果你使用的话,这应该为前端的实例化表单提供尽可能多的<input name='this_field'>
:
{{ form.this_field }}
在模板中,但不会动态添加/删除它们。
为了做到这一点,你必须插入在小部件中动态添加/删除输入所需的JavaScript,但我会将此作为练习。查看文档中的Form Assets (the Media class)以了解如何执行此操作。
答案 1 :(得分:1)
我认为你要找的是formsets。 https://docs.djangoproject.com/en/2.0/topics/forms/formsets/
from django.forms import formset_factory
ItemFormSet = formset_factory(ItemForm, extra=2)
除了这个对象是 iterable 之外,您可以按照使用普通表单的方式使用ItemFormSet。
如果要动态添加项目,还必须更改jquery。网上有很多关于如何做到这一点的例子。简而言之,你做的是
使用Formsets并不能解决获取和验证的问题 具有相同名称的字段。问题仍然存在
然而,它会产生您想要的最终结果(见下文)。我的问题是你需要输入相同名称的原因?如果有一些jquery的东西使用这些名称,我没有看到任何理由你不能使用像...这样的名称或者为输入分配一个类。
def pickup_order_view(request):
if request.method == 'GET':
ItemFormSet = formset_factory(ItemForm, extra=5)
item_formset = ItemFormSet()
template = "some_template.html"
template_context = {'item_formset': item_formset}
return render(request, template, template_context)
if request.method == 'POST':
ItemFormSet = formset_factory(ItemForm)
item_formset = ItemFormSet(request.POST)
same_name_fields=[]
if item_formset.is_valid():
for item_form in item_formset:
same_name_fields.append(item_form.cleaned_data['this_field'])
print(same_name_fields)
模板
<form id = "orderForm" action="newPickupOrder/" method="post" name="processForm">
{% csrf_token %}
{{ item_formset.management_form }}
{{ for item_form in item_formset }}
{{ item_form.as_p }}
{{ endfor }}
<input type='submit' value='submit'>
</form>
转到newPickupOrder /,填写5个字段,点击提交,然后观看它打印列表。