在Django中,如何从模型/子项预先填充编辑表单,但将提交保存为新实例?

时间:2009-04-26 02:10:43

标签: django django-models django-forms

我正在尝试使用Model的实例预填充ModelForm和inlineformset_factory,但是当用户提交表单时,我需要创建Model的新实例及其相关的子记录。

示例模型:

class Artist(models.Model):
    artist = models.CharField(max_length=100)

class Song(models.Model):
    artist = models.ForeignKey(Artist)
    song = models.CharField(max_length=200)

我希望用户看到基于Artist实例的编辑表单,以及该Artist相关歌曲的InlineFormSet。表格将预填充现有数据,用户可以更改艺术家的姓名和歌曲名称。但是,当用户提交表单时,我不想覆盖现有记录。相反,我想创建一个艺术家的新实例,并为这位新艺术家添加新的歌曲。

我在保存之前尝试将艺术家的主键设置为无 - 这会强制执行艺术家的新实例。但是,我失去了艺术家和歌曲之间的ForeignKey关系。

示例视图:

def edit(request, artist_id=None):
    if  artist_id == None:
        artistsubmission = Artist()
    else:
        artistsubmission = Artist.objects.get(id = artist_id)
        artistsubmission.pk = None

    if request.method == 'POST':
        form = ArtistEditForm(request.POST, instance=artistsubmission)
        formset = SongFormSet(request.POST, instance=artistsubmission)

        if form.is_valid() and formset.is_valid():
            form.save()
            formset.save()
            return HttpResponseRedirect('/success/')    
    else:
        form = ArtistEditForm(instance=artistsubmission)
        formset = SongFormSet(instance=artistsubmission)

    return render_to_response('edit.html', {'form':form, 'formset':formset})

4 个答案:

答案 0 :(得分:4)

您可以迭代formset中的各个表单,更改您需要的内容并保存。

if form.is_valid() and formset.is_valid():
    artist = form.save()
    for f in formset.forms:
        song = f.save(commit=False)
        song.artist = artist.id
        song.save()

答案 1 :(得分:2)

我认为最简单的方法是通过将字典作为第一个参数传递给表单来设置默认值。您可以通过以下方式获取模型实例的所有字段:

d_initial = Artist.objects.filter(pk=artist_id).values()[0]

这是您传入表单的字典。

form = ArtistEditForm(d_initial)

如果您从表单中排除了任何内容,则可能需要将其从字典中删除。 id也是如此。但是这应该生成一个包含现有实例中所有值的表单,但会保存到新实例。

答案 2 :(得分:1)

我有类似的问题,我解决了这个问题:

def edit(request, artist_id=None):
    if artist_id == None:
        artistsubmission = Artist()
    else:
        artistsubmission = get_object_or_404(Artist, id = artist_id)

    if request.method == 'POST':
        form = ArtistEditForm(request.POST, instance=artistsubmission)
        formset = SongFormSet(request.POST, instance=artistsubmission)

        if form.is_valid() and formset.is_valid():
            artistsubmission.pk = None

            artist = form.save(commit=False)
            artist.id = None
            artist.save()

            for f in formset.forms:
                song = f.save(commit=False)
                song.artist_id = artist.id
                song.id = None
                song.save()
            return HttpResponseRedirect('/success/')
    else:
        form = ArtistEditForm(instance=artistsubmission)
        formset = SongFormSet(instance=artistsubmission)
    return render_to_response('edit.html', {'form':form, 'formset':formset})

答案 3 :(得分:0)

我发现这个片段我认为更符合您的要求。 http://www.djangosnippets.org/snippets/1246/