【问题标题】:Edit a formset in django在 django 中编辑表单集
【发布时间】:2020-07-25 18:20:17
【问题描述】:

在我的 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})

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

【问题讨论】:

    标签: django django-forms formset


    【解决方案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)
    

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

    如果您有任何问题,请不要犹豫

    【讨论】:

    • 您好,感谢您的回答。我尝试了您的解决方案,但它只在表单中显示团队名称,而不是团队中的Players。我已经用您的解决方案更新了问题
    • 请你告诉我怎样才能得到球员??
    • 对不起,我不能帮你。一个提示是您应该创建一个单独的视图和表单来创建一个播放器。在这里混合使用它们会更难调试,因为您正在增加正在学习的新主题的复杂性
    【解决方案2】:

    如果需要,则必须将填写的表单传回模板。文档中的一个很好的例子是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})
    

    我改变了一些东西。首先,对基于函数的视图使用小写字母,并尽量不要在视图中使用名称“表单”。此外,请注意缩进:“if form.player_instances.cleaned_data...”有一个额外的缩进。如果没有球队,检查球员没有多大用处,你将无法拯救(不存在的)球队。然后:'return' 语句现在与第一个 if/else 语句处于同一级别。在您的版本中,保存表单后没有返回。通过这样做,已填写的表单(来自语句的 if 部分)在上下文变量中返回。然后,模板的工作就是决定如何处理它。在 else 情况下,返回一个空表单。

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

    【讨论】:

    • 嗨,保罗,感谢您的回答,但我认为您误解了这个问题。我可以保存表单,但是在编辑保存的对象时我没有运气。我尝试了 Matthieu 的答案,它只检索了tname,我需要帮助来检索表单中的玩家namesagehighest score,以便我可以编辑它们。另外,我已经用模板更新了问题,以便您可以更好地帮助我
    【解决方案3】:

    除了 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

    【讨论】:

    • 我尝试了 Matthieu 的回答,但它只初始化了 tname 而不是 m2m 连接的实例
    • 是的,因此我建议提到的其他更改应该可以用于获取属于团队的球员
    • 我仍然不清楚如何做到这一点,你能显示一些代码吗?
    • 我尝试了modelformset,但为什么它会从数据库中获取所有实例?
    • 因为在实例化modelformset docs.djangoproject.com/en/3.0/topics/forms/modelforms/…时没有指定queryset
    猜你喜欢
    • 2018-01-29
    • 2018-09-06
    • 1970-01-01
    • 2018-12-12
    • 2018-12-03
    • 1970-01-01
    • 1970-01-01
    • 2016-10-23
    • 2013-04-12
    相关资源
    最近更新 更多