1

我有两个模型PublisherBook如下所示

模型.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

但我面临以下不同的问题

  1. 当我们点击Add another item按钮时,一个新的表单已经成功创建。
  2. 当我们使用 提交表单时empty datavalidation错误消息会正确显示在相应的下方fields

问题一

  1. 现在,当我们尝试这样做时add another form,包括错误消息在内的所有以前的表单都将再次重新显示

就像我们有two表单,当我们在submit没有数据的情况下单击时,会为两个表单生成验证错误消息,现在当我们单击时Add another item,完全four forms已创建,我的意思是重复先前创建的两个表单,包括验证消息

问题二

  1. 所以现在当我们尝试删除表单时,我的意思是当我们点击delete表单按钮时,这种情况下的所有表单(如4 forms)都被删除了?

那么你怎么能让我知道如何解决这个问题?

4

1 回答 1

1

问题是获取所有元素以更改前缀计数器的代码实际上并未选择任何元素。

deleteForm 的变化:

forms.get(i)).children().children().each

至:

forms.get(i)).find('input,select,textarea').each

并更改addForm:

$(row).children().children().each

至:

$(row).find('input,select,textarea').each

这将选择将包含在 POST 到服务器的表单中的所有元素。

于 2013-10-26T13:29:59.013 回答