在Django中编辑表单集

时间:2020-04-13 07:59:56

标签: django django-forms formset

在我的django应用中,我试图理解多对多的关系,并且我使用formset来存储数据,如下所示:

Views.py

def Team_Form(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, 'packsapp/employee/new.html', {'form':form})

Models.py

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

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

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>
                <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) {
                                    console.log("id", id)
                                    var idData = id;
                                    var splitV = String(idData).split('-');
                                    var fData = splitV[0];
                                    var tData = splitV[2];
                                    return fData + "-" + index + "-" + tData
                                },
                                'name': function (_, name) {
                                    console.log("name", 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) {
                        console.log("id", id)

                        var idData = id;
                        var splitV = String(idData).split('-');
                        var fData = splitV[0];
                        var tData = splitV[2];
                        return fData + "-" + i + "-" + tData
                    },
                    'name': function (_, name) {
                        console.log("name", 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);
        $("tbody tr:last :input").each(function () {
            $(this).attr({
                'id': function (_, id) {
                    return id.replace(/\d/g, i)
                },
                'name': function (_, name) {
                    return name.replace(/\d/g, i)
                },
            })
        })

        i++;

    });
</script>

</body>
</html>

我无法理解的是,如何编辑刚刚保存的表单集,或者更好地表达问题:如何将保存的实例传递给表单集以进行编辑?

更新

我尝试了modelformset_factory,并在发布以及更新后从Player获取所有对象

Forms.py

PlayerFormset= modelformset_factory(Player, fields=('pname','hscore','age'))

屏幕截图:

试图编辑团队Matt

enter image description here

3 个答案:

答案 0 :(得分:1)

这里的多对多意味着一个球员可以在多个团队中,而且一个团队可以有很多球员。

要解决您的问题,您必须创建另一个视图(链接到相同的表单),该视图将显示您的表单但已经填写。 在您的团队的功能pk中。

def updateTeam(request,pk):

  team = Team.objects.get(id=pk)
  form = TeamForm(instance=team)


if request.method == "POST":
    form = TeamForm(request.POST, instance=team)
    if form.is_valid():
        form.save()

context = {'form': form}
return render(request, 'accounts/order_form.html', context)

那应该可以解决您的问题!

如有任何疑问,请不要犹豫

答案 1 :(得分:0)

如果需要,则必须将填写的表单传递回模板。文档中的一个很好的例子是https://docs.djangoproject.com/en/3.0/topics/forms/formsets/#using-a-formset-in-views-and-templates。在您的代码中,它看起来像这样(尚未尝试使用模板):

def team_view(request):
    PlayerFormset = formset_factory(PlayerForm)

    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, 'packsapp/employee/new.html', {'form': form})

我做了几件事。首先,对于基于函数的视图,请使用小写字母,并尽量不要在视图中使用名称“ form”。此外,请注意缩进:'if form.player_instances.cleaned_data ...'还有一个额外的缩进。如果没有团队,检查玩家的用处不大,您将无法保存(不存在)团队。然后:'return'语句现在与第一个if / else语句处于同一级别。在您的版本中,保存表单后没有任何回报。这样,将在上下文变量中返回填充形式(来自语句的if部分)。然后,决定模板的工作是模板的工作。在其他情况下,将返回一个空表格。

我注意到该项目显然是一个教程,关于StackOverflow至少有两个相关问题:Django Dynamic form for manytomany relationshipHow can i save django dynamic formset data using forms and views。也许你可以从中学到东西。

答案 2 :(得分:0)

除了Matthieu-OD的答案https://stackoverflow.com/a/61185348/13168118

您可以更改

PlayerFormset= formset_factory(PlayerForm)

modelformset_factory

https://docs.djangoproject.com/en/3.0/ref/forms/models/#django.forms.models.modelformset_factory

,并且在“ TeamForm”的init方法中,您应该能够调整modelformset的查询集,使其仅显示该团队的球员

如果不进行调整,将向每个玩家显示

编辑:

我还建议您使用模型形式,因为您的形式用于模型: https://docs.djangoproject.com/en/3.0/topics/forms/modelforms/#modelform

我也发现了这个问题,看起来很相似: Django ModelForm for Many-to-Many fields