我有两个模型Publisher
,Book
如下所示
模型.py
class Publisher(models.Model):
name = models.CharField(max_length=255)
class Book(models.model):
name = models.CharField(max_length=255)
price = models.DecimalField()
generic = generic.GenericForeignKey()
publisher_id = models.PositiveIntegerField()
表格.py
class PublisherForm(ModelForm):
model = Publisher
class BookForm(ModelForm):
model = Book
exclude = ('generic', 'publisher_id',)
def __init__(self, *args, **kwargs):
super(BookForm, self).__init__(*args, **kwargs)
self.fields['name'].widget.attrs = {'id':'inputId', 'class':'input-block-level, 'placeholder':'Name'}
self.fields['name'].error_messages = {'required': 'Please enter name'}
self.fields['age'].widget.attrs = {'id':'inputId', 'class':'input-block-level, 'placeholder':'Age'}
self.fields['age'].error_messages = {'required': 'Please enter age'}
视图.py
在此视图中,我将发送发布者 ID,因为Book
模型没有发布者模型 的外键
from .forms import BookForm
@login_required
def create_multiple_books(request, publisher_id):
class RequiredFormSet(BaseFormSet):
def __init__(self, *args, **kwargs):
super(RequiredFormSet, self).__init__(*args, **kwargs)
for form in self.forms:
form.empty_permitted = False
BookFormset = formset_factory(BookForm, max_num=10, formset=RequiredFormSet)
if request.method == 'POST':
book_formset = BookFormset(request.POST, request.FILES)
if book_formset.is_valid():
for form in book_formset.forms:
obj = form.save(commit=False)
obj.publisher_id = publisher_id
obj.save()
return redirect(reverse('created'))
else:
book_formset = BookFormset()
c = {'book_formset': book_formset,
'publisher_id':publisher_id,
}
c.update(csrf(request))
return render_to_response('add_books.html',c,context_instance = RequestContext(request))
模板.html
因此,在下面的模板中,将表单呈现为form.as_p
正常工作,并且publisher id
成功创建了多个记录
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
// Code adapted from http://djangosnippets.org/snippets/1389/
function updateElementIndex(el, prefix, ndx) {
var id_regex = new RegExp('(' + prefix + '-\\d+-)');
var replacement = prefix + '-' + ndx + '-';
if ($(el).attr("for")) $(el).attr("for", $(el).attr("for").replace(id_regex,
replacement));
if (el.id) el.id = el.id.replace(id_regex, replacement);
if (el.name) el.name = el.name.replace(id_regex, replacement);
}
function deleteForm(btn, prefix) {
var formCount = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
if (formCount > 1) {
// Delete the item/form
$(btn).parents('.item').remove();
var forms = $('.item'); // Get all the forms
// Update the total number of forms (1 less than before)
$('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
var i = 0;
// Go through the forms and set their indices, names and IDs
for (formCount = forms.length; i < formCount; i++) {
$(forms.get(i)).children().children().each(function() {
updateElementIndex(this, prefix, i);
});
}
} // End if
else {
alert("You have to enter at least one todo item!");
}
return false;
}
function addForm(btn, prefix) {
var formCount = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
// You can only submit a maximum of 10 todo items
if (formCount < 10) {
// Clone a form (without event handlers) from the first form
var row = $(".item:first").clone(false).get(0);
// Insert it after the last form
$(row).removeAttr('id').hide().insertAfter(".item:last").slideDown(300);
// Remove the bits we don't want in the new row/form
// e.g. error messages
$(".errorlist", row).remove();
$(row).children().removeClass('error');
// Relabel/rename all the relevant bits
$(row).children().children().each(function() {
updateElementIndex(this, prefix, formCount);
if ( $(this).attr('type') == 'text' )
$(this).val('');
});
// Add an event handler for the delete item/form link
$(row).find('.delete').click(function() {
return deleteForm(this, prefix);
});
// Update the total form count
$('#id_' + prefix + '-TOTAL_FORMS').val(formCount + 1);
} // End if
else {
alert("Sorry, you can only enter a maximum of ten items.");
}
return false;
}
// Register the click event handlers
$("#add").click(function() {
return addForm(this, 'form');
});
$(".delete").click(function() {
return deleteForm(this, 'form');
});
});
</script>
</head>
<body>
<form action="" method="POST">{% csrf_token %}
<div class="section">
{{ todo_list_form.as_p }}
</div>
<h2>Todo Items</h2>
{{ book_formset.management_form }}
{% for form in book_formset.forms %}
<div class="item">
{{ form.as_p }}
<p style=""><a class="delete" href="#">Delete</a></p>
</div>
{% endfor %}
<p><a id="add" href="#">Add another item</a></p>
<input type="submit" value=" Submit " />
</form>
</body>
</html>
但是当我从表单中显示 html 字段并呈现如下
{% for form in book_formset.forms %}
<div class="item">
<div class="with_name_design">{{ form.name }}</div>
{% if form.name.errors %}
{{form.name.errors}}
{% endif %}
<div class="with_age_design">{{ form.age }}</div>
{% if form.age.errors %}
{{form.age.errors}}
{% endif %}
</div>
{% endfor %}
表单显示成功,当我单击链接时,Add another item
正在使用上面的 jquery 生成一个新表单,当我尝试通过输入所有详细信息并单击提交来提交时,jquery 添加的下一个表单正在显示验证错误像name, age is required
?(这仅在这种情况下发生,即单独显示字段而不是 form.as_p(),如果我们呈现为 form.as_p(),它的工作正常并且记录正在创建到数据库中)
所以我真的无法弄清楚为什么当我渲染表单时它成功了form.as_p()
,为什么当我渲染时不成功individual fields with their errors
我是否遗漏了上述 javascript 代码中的任何内容/需要以及生成其他表单的任何内容?
因为当我们单独渲染字段时,通过单击添加另一个表单按钮生成的表单显示验证错误?
我真的浪费了很多时间来弄清楚上面的javascript,因为我通过谷歌搜索得到了一些地方,
所以最后当我们将formset表单渲染为时,上述功能是有效的form.as_p()
,但是当我们单独渲染表单字段时,为什么上述功能不起作用?
任何人都可以让我知道如何解决上述问题(也可能是上面的代码将有助于许多用户动态创建表单,就像我们在 django admin 中有内联表单一样)
编辑
K谢谢schillingt,
所以根据你下面的回答,我修改了javascript和html,如下所示
{% for form in book_formset.forms %}
<div class="item">
<div class="with_name_design">{{ form.name }}</div>
{% if form.name.errors %}
<span>{{form.name.errors.0}}</span>
{% endif %}
<div class="with_age_design">{{ form.age }}</div>
{% if form.age.errors %}
<span>{{form.age.errors.0}}</span>
{% endif %}
</div>
{% endfor %}
并且表单在之后呈现错误form validation
但我面临以下不同的问题
- 当我们点击
Add another item
按钮时,一个新的表单已经成功创建。 - 当我们使用 提交表单时
empty data
,validation
错误消息会正确显示在相应的下方fields
问题一
- 现在,当我们尝试这样做时
add another form
,包括错误消息在内的所有以前的表单都将再次重新显示
就像我们有two
表单,当我们在submit
没有数据的情况下单击时,会为两个表单生成验证错误消息,现在当我们单击时Add another item
,完全four forms
已创建,我的意思是重复先前创建的两个表单,包括验证消息
问题二
- 所以现在当我们尝试删除表单时,我的意思是当我们点击
delete
表单按钮时,这种情况下的所有表单(如4 forms
)都被删除了?
那么你怎么能让我知道如何解决这个问题?