Initialize a formset

笑着哭i 提交于 2020-05-29 07:48:57

问题


I have two models connected by manytomany relationship and I am trying to use formset to create a dynamic form. I am able to save the form but the problem arise when I am trying to edit the saved instance, I don't know how to properly pass the instance to the formset such that it shows the instance data in form for editing

Here are the details:

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.ModelForm):

    class Meta:
        model = Player
        fields = '__all__'

PlayerFormset= formset_factory(PlayerForm)

class TeamForm(forms.ModelForm):

   player= PlayerFormset()
   class Meta:
       model = Team
       fields = '__all__'
       exclude = ["player"]

Views.py

def team(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})


def updateTeam(request,pk):

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

// something here to initialize the formset ??

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

    context = {'form': form}
    return render(request, 'packsapp/employee/new.html', context)

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>

update:

Use modelformset_factory in the views directly:

def post(request):
    tform = TeamForm()
    pform = modelformset_factory(Player, form=PlayerForm, extra = 1)
    pform = pform(request.POST or None, queryset = Player.objects.filter(id__isnull = True))
    if request.method == 'POST':
        t = Team()
        tform = TeamForm(request.POST, instance=t)
        if tform.is_valid() and pform.is_valid():
            tform.save()
            instances = pform.save(commit=False)
            for i in instances:
                player = Player()
                player.pname = i.pname
                player.hscore = i.age
                player.age = i.hscore
                player.save()
                t.player.add(player)
            t.save()
            return redirect('/exams/dashboard/')
        else:
            print('invalid data')
    return render(request, 'team/team_create.html', {'exform': tform, 'exformset': pform})


def update(request, pk = None):
    team = Team.objects.get(id = pk)
    tform = TeamForm(instance = team)
    pform = modelformset_factory(Player, form=PlayerForm, extra=0)
    print("players", Player.objects.filter(team=team))
    pform = pform(request.POST or None, queryset=Player.objects.filter(team=team))
    if request.method == 'POST':
        tform = TeamForm(request.POST, instance=team)
        print("tform ", tform)
        print("pform ", pform)
        if tform.is_valid() and pform.is_valid():
            tform.save()
            instances = pform.save(commit=False)
            for i in instances:
                player = Player()
                player.pname = i.pname
                player.hscore = i.age
                player.age = i.hscore
                player.save()
                t.player.add(player)
            t.save()
            return redirect('/exams/dashboard/')
        else:
            print('invalid data')
    return render(request, 'team/team_create.html', {'exform': tform, 'exformset': pform})

回答1:


The TeamForm has to set the queryset of the PlayerFormset. The following shows how.

  class TeamForm(forms.ModelForm):
      player= PlayerFormset()
      class Meta:
          model = Team
          fields = '__all__'
          exclude = ["player"]
      def __init__(self,*args, **kwargs):
          super(TeamForm,self).__init__(*args,**kwargs)
          self.player = PlayerFormSet(queryset=Players.objects.filter(team=self.instance)

Information from the documentation: https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#changing-the-queryset

maybe also worth a look: https://stackoverflow.com/a/34323401/13168118

EDIT:

your PlayerFormset should be created with a modelformset_factory like:

PlayerFormset = modelformset_factory(Player, form=PlayerForm)

modelformset documentation: https://docs.djangoproject.com/en/2.2/ref/forms/models/#modelformset-factory



来源:https://stackoverflow.com/questions/61285171/initialize-a-formset

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!