在一个 html 表单中处理多个模型表单

Handle multiple modelforms in one html form

用户将拥有与其特定相册相关的照片。

这就是模型:

class Album(models.Model):
    user = models.ForeignKey(User)
    title = models.CharField(max_length=200)
    pub_date = models.DateTimeField(auto_now_add=True, auto_now=False)
    update = models.DateTimeField(auto_now_add=False, auto_now=True)

class Photo(models.Model):
    photo_privacy = models.CharField(max_length=1,choices=PRIVACY, default='F')
    user = models.ForeignKey(User)
    caption = models.TextField()
    image = models.ImageField(upload_to=get_upload_file_name)
    pub_date = models.DateTimeField(auto_now_add=True, auto_now=False)

Views.py:

def create_album(request, user_name):
    user = User.objects.get(username=unquote(user_name))
    if request.method=='POST':
        pform = AlbumPhotoForm(request.POST, request.FILES)
        aform = AlbumForm(request.POST)
        p_valid = pform.is_valid()
        a_valid = aform.is_valid()
        if p_valid and a_valid:
            photo = pform.save(commit=False)
            album = aform.save(commit=False)
            photo.user = user
            album.user = user
            album.save()
            photo.album = album
            photo.save()
            return HttpResponseRedirect('/'+user.username+'/photos')
        else:
            return render(request, 'create_album.html',{
                'pform':pform,
                'aform':aform
            })
    else:
        pform = AlbumPhotoForm()
        aform = AlbumForm()
        return render(request, 'create_album.html', {
            'pform':pform,
            'aform':aform
        })

和表格:

<form action="/{{ user.username }}/create_album/" method="post" enctype="multipart/form-data">
{% csrf_token %}
    {{ aform.as_p }}

    {{ pform.as_p }}
    <input type="submit" value="Create and Upload Album"/>
</form>

如果我只需要用那个表格上传一个文件(照片),这很好用。

更新:

但是我想做的是,显示至少三个用于将照片上传到新相册的输入:

<form action="/{{ user.username }}/create_album/" method="post" enctype="multipart/form-data">
{% csrf_token %}
    {{ aform.as_p }}

    {{ pform.as_p }}
    {{ pform.as_p }}
    {{ pform.as_p }}
    <input type="submit" value="Create and Upload Album"/>
</form>

这样做时,只会保存最后一个 pform。其他两个 pform 被忽略。如何相应地保存所有三种形式的照片 (pform)?

或者有其他办法吗?非常感谢您的帮助!谢谢。

使用formsets。他们做的正是你想要的:

from django.forms.models import formset_factory

PhotoFormSet = formset_factory(AlbumPhotoForm, can_delete=False,
                               min_num=1, validate_min=True,
                               max_num=3, validate_max=True,
                               extra=3)

def create_album(request, user_name):
    user = User.objects.get(username=unquote(user_name))
    if request.method=='POST':
        form = AlbumForm(request.POST)
        formset = PhotoFormSet(request.POST, request.FILES)
        if all([form.is_valid(), formset.is_valid()]):
            album = form.save(commit=False)
            album.user = user
            album.save()
            for photo_form in formset:
                if photo_form.cleaned_data:
                    photo = photo_form.save(commit=False)
                    photo.album = album
                    photo.user = user
                    photo.save()
            return redirect('/%s/photos' % user.username )
    else:
        form = AlbumForm()
        formset = PhotoFormSet()
    return render(request, 'create_album.html',
                  {'form': form, 'formset': formset})

模板可能如下所示:

<form action="." method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.as_p }}    
    <table>
        {{ formset }}
    </table>    
    <input type="submit" value="Create and Upload Album"/>
</form>