在创建一个表单集Django的形式动态地就像在Django管理在线形式与jQuery(creatin

2019-10-18 20:44发布

我有两个型号PublisherBook像下面

models.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()

forms.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'}  

views.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))  

template.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 ?(这是在这种情况下是显示领域seperately代替form.as_p()只发生,如果我们呈现为form.as_p()其工作正常,并记录在创建数据库)

所以,我真的无法弄清楚它为什么当我呈现的形式是succeded form.as_p()为什么不是我呈现individual fields with their errors

我失去了产生另一种形式的javascript代码高于一切/需要和任何在?

因为当我们单独呈现的字段,通过点击添加其他形式的按钮显示验证错误产生的形式?

我真的浪费了大量的时间搞清楚以上的JavaScript,因为我得到了它的一些地方通过谷歌搜索周围,

所以最后上述functionlality工作当我们在表单集形式form.as_p()但为什么当我们单独渲染表单字段上述功能无法正常工作?

任何人都可以请让我知道如何解决上述问题(也可能是上面的代码将是有用的形式很多用户动态创建的形式就像我们在Django管理在线表单)

编辑

ķ感谢schillingt,

因此,根据下面的UR答案有我修改的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 data时, validation正确显示相应的提示以下错误消息fields

一个问题

  1. 现在,当我们尝试add another form ,以前的所有形式,包括错误消息再次重新显示

就像如果我们有two的形式,当我们点击submit没有数据,验证错误消息产生两种形式,现在马上当我们点击Add another item ,共four forms已经建立,我的意思是以前创建了两个形式被重复包括验证消息

发出两个

  1. 所以,现在马上当我们试图删除一个形式,我的意思是,当我们点击delete表单按钮,所有的形式(如4 forms在这种情况下)被删除?

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

Answer 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到服务器的表单元素。



文章来源: creating a django form in formset dynamically like inline forms in django admin with jquery