如何使用表单和视图保存django动态formset数据

时间:2017-12-11 07:27:33

标签: javascript jquery python django django-forms

我正在尝试使用表单和视图保存formset额外字段数据。 例如: - 队员没有球员。所以我想通过点击添加更多按钮添加新的播放器。我尝试下面的代码。问题是如果我一次添加多个玩家......它只保存最后一个对象值 o/p for below code

models.py

from django.db import models

class Player(models.Model):
    pname = models.CharField(max_length=50)
    hscore = models.IntegerField()
    age = models.IntegerField()
    def __str__(self):
       return self.pname

class Team(models.Model):
    tname = models.CharField(max_length=100)
    player= models.ManyToManyField(Player)
    def __str__(self):
        return self.tname

forms.py

from django import forms
from django.forms.formsets import formset_factory

class PlayerForm(forms.Form):
    pname = forms.CharField()
    hscore= forms.IntegerField()
    age = forms.IntegerField()

PlayerFormset= formset_factory(PlayerForm)

class TeamForm(forms.Form):
   tname= forms.CharField()
   player= PlayerFormset()

views.py

from django.shortcuts import render, get_object_or_404,redirect
from .models import Player,Team
from .forms import TeamForm,PlayerFormset
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django import forms
from django.forms import formset_factory

def post(request):

   if request.POST:
        form = TeamForm(request.POST)
        form.player_instances = PlayerFormset(request.POST)
        if form.is_valid():
        team= Team()
        team.tname= form.cleaned_data['tname']
        team.save()

        if form.player_instances.cleaned_data is not None:

            for item in form.player_instances.cleaned_data:
                player = Player()
                player.pname= item['pname']
                player.hscore= item['hscore']
                player.age= item['age']
                player.save()
                team.player.add(player)
            team.save()

   else:
        form = TeamForm()
        return render(request, 'new.html', {'form':form})

模板:new.html

<html>
<head>

    <title>gffdfdf</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

 </head>
<body>

 <div class="container">

 <form action="" method="post" class="">
 {% csrf_token %}
  <h2> Team</h2>
   {% for field in form %}
   {{ field.errors }}
   {{ field.label_tag }} : {{ field }}
    {% endfor %}
  {{ form.players.management_form }}

  <h3> Product Instance(s)</h3>
  <table id="table-product" class="table">
    <thead>
       <tr>
          <th>player name</th>
         <th>highest score</th>   
         <th>age</th>
       </tr>

     </thead>
      {% for player in form.players %}
       <tbody class="player-instances">

    <tr> 
        <td>{{ player.pname  }}</td>
        <td>{{ player.hscore }}</td>   
         <td>{{ player.age }}</td>
         <td> <input id="input_add" type="button" name="add" value=" Add More " class="tr_clone_add btn data_input"> </td>
      </tr>

      </tbody>
 {% endfor %}
    </table><button type="submit" class="btn btn-primary">save</button>

   </form>
   </div>
   <script>
       var i = 1;
    $("#input_add").click(function() {
        $("tbody tr:first").clone().find(".data_input").each(function() {
            if ($(this).attr('class')== 'tr_clone_add btn data_input'){
                $(this).attr({
                    'id': function(_, id) { return "remove_button" },
                    'name': function(_, name) { return "name_remove" +i },
                    'value': 'Remove'
                }).on("click", function(){
                    var a = $(this).parent();
                    var b= a.parent();
                    i=i-1
                    $('#id_form-TOTAL_FORMS').val(i);
                    b.remove();

                    $('.player-instances tr').each(function(index, value){
                        $(this).find('.data_input').each(function(){
                            $(this).attr({
                                'id': function (_, id) {
                                     var idData= id;
                                    var splitV= String(idData).split('-');
                                    var fData= splitV[0];
                                    var tData= splitV[2];
                                    return fData+ "-" +index + "-" + tData
                                },
                                'name': function (_, name) {
                                    var nameData= name;
                                    var splitV= String(nameData).split('-');
                                    var fData= splitV[0];
                                    var tData= splitV[2];
                                    return fData+ "-" +index + "-" + tData
                                }
                            });
                        })
                    })
                })
            }
            else{
                $(this).attr({
                    'id': function (_, id) {
                        var idData= id;
                        var splitV= String(idData).split('-');
                        var fData= splitV[0];
                        var tData= splitV[2];
                        return fData+ "-" +i + "-" + tData
                    },
                    'name': function (_, name) {
                        var nameData= name;
                        var splitV= String(nameData).split('-');
                        var fData= splitV[0];
                        var tData= splitV[2];
                        return fData+ "-" +i + "-" + tData
                    }
                });

            }
        }).end().appendTo("tbody");
        $('#id_form-TOTAL_FORMS').val(1+i);
        i++;

    });
</script>
</body>
</html>

=============================================== ================

我无法保存所有对象。请更正

3 个答案:

答案 0 :(得分:0)

您需要遍历form.player_instances。

if request.POST:
    form = TeamForm(request.POST)
    form.player_instances = PlayerFormset(request.POST)
    if form.is_valid():
    team= Team()
    team.tname= form.cleaned_data['tname']
    team.save()

    if form.player_instances.is_valid():

        for item in form.player_instances:
            player = Player()
            player.pname= item.cleaned_data['pname']
            player.hscore= item.cleaned_data['hscore']
            player.age= item.cleaned_data['age']
            player.save()
            team.player.add(player)
            team.save()

答案 1 :(得分:0)

您只能保存第一个项目的原因是您添加的行ID,名称仍为id_form-0-pname而不是更改为id_form-1-pname(模式为id_form-i-pname)。

实现此目的的另一种方法是使用lib django-dynamic-formset,代码在这里:

news.html

<html>
<head>

    <title>gffdfdf</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="/static/jquery.formset.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

</head>
<body>

<div class="container">

    <form id="myForm" action="" method="post" class="">
        {% csrf_token %}
        <h2> Team</h2>
        {% for field in form %}
            {{ field.errors }}
            {{ field.label_tag }} : {{ field }}
        {% endfor %}
        {{ form.player.management_form }}

        <h3> Product Instance(s)</h3>
        <table id="table-product" class="table">
            <thead>
            <tr>
                <th>player name</th>
                <th>highest score</th>
                <th>age</th>
            </tr>

            </thead>
            {% for player in form.player %}
                <tbody class="player-instances">

                <tr>
                    <td>{{ player.pname }}</td>
                    <td>{{ player.hscore }}</td>
                    <td>{{ player.age }}</td>
                </tr>

                </tbody>
            {% endfor %}
        </table>
        <button type="submit" class="btn btn-primary">save</button>

    </form>
</div>
<script>
    $(function () {
        $('#myForm tbody tr').formset();
    })
</script>
</body>
</html>

看起来像enter image description here 这很简单,也很有效。 可以从here的github下载jquery.formset.js。文档为here。  您可以使用conf jquery.formset.js更改添加\删除链接的文本和CSS,如:

/* Setup plugin defaults */
$.fn.formset.defaults = {
    prefix: 'form',                  // The form prefix for your django formset
    formTemplate: null,              // The jQuery selection cloned to generate new form instances
    addText: 'add another',          // Text for the add link
    deleteText: 'remove',            // Text for the delete link
    addCssClass: 'add-row',          // CSS class applied to the add link
    deleteCssClass: 'delete-row',    // CSS class applied to the delete link
    formCssClass: 'dynamic-form',    // CSS class applied to each form in a formset
    extraClasses: [],                // Additional CSS classes, which will be applied to each form in turn
    keepFieldValues: '',             // jQuery selector for fields whose values should be kept when the form is cloned
    added: null,                     // Function called each time a new form is added
    removed: null                    // Function called each time a form is deleted
};

答案 2 :(得分:0)

**对您的new.html文件使用以下内容,并保持其他文件(如表单和模型)不变

<html>
<head>

    <title>gffdfdf</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.formset/1.2.2/jquery.formset.js"></script>

</head>
<body>

<div class="container">

    <form method="post" class="">
        {% csrf_token %}
        <h2> Team</h2>
        {% for field in form %}
            {{ field.errors }}
            {{ field.label_tag }} : {{ field }}
        {% endfor %}
        {{ form.players.management_form }}
       <div style="display: none" > {{ form.players.empty_form }}</div>

        <h3> Product Instance(s)</h3>
        <table id="table-product" class="table">
            <thead>
            <tr>
                <th>player name</th>
                <th>highest score</th>
                <th>age</th>
            </tr>

            </thead>
            {% for player in form.players %}
                <tbody class="player-instances" id="playerFrmTableId">

                <tr>
                    <td>{{ player.pname  }}</td>
                    <td>{{ player.hscore }}</td>
                    <td>{{ player.age }}</td>
                    <td> <input id="input_add" type="button" name="add" value=" Add More " class="tr_clone_add btn data_input"> </td>
                </tr>


                </tbody>
            {% endfor %}
        </table><button type="submit" class="btn btn-primary">save</button>

    </form>
</div>
<script>

    $("#input_add").click(function() {
        let formCount = parseInt($('#id_form-TOTAL_FORMS').val());
        var html = `<tr>
                        <td>{{ form.players.empty_form.pname }}</td>
                        <td>{{ form.players.empty_form.hscore }}</td>
                        <td>{{ form.players.empty_form.age }}</td>
                        <td> <input id="input_add" type="button" name="add" value=" Add More " class="tr_clone_add btn data_input"> </td>
                     </tr>`;
       html =  html.replace(/__prefix__/g, formCount);
        $('#id_form-TOTAL_FORMS').val(formCount + 1);
        $('#playerFrmTableId').append(html);
    });
</script>
</body>
</html>