Django根据添加表单编辑表单?

48 投票
2 回答
58083 浏览
提问于 2025-04-15 16:43

我做了一个不错的表单,还有一个复杂的“添加”功能来处理它。这个功能是这样开始的……

def add(req):
    if req.method == 'POST':
        form = ArticleForm(req.POST)
        if form.is_valid():
            article = form.save(commit=False)
            article.author = req.user
            # more processing ...

现在我不想在edit()方法里重复所有这些功能,所以我想edit可以用完全相同的模板,也许只需要在表单中添加一个id字段,这样add功能就知道它在编辑什么。但是这样做有几个问题:

  1. 我该在哪里设置article.id呢?它必须在form.save之后,因为这是创建文章的地方,但实际上它根本不会到达那里,因为表单因为唯一性限制而无效(除非用户编辑了所有内容)。我可以直接去掉is_valid的检查,但那样form.save就会失败。
  2. 如果表单实际上无效的,我在编辑功能中动态添加的字段就不会被保留。

那我该怎么处理这个呢?

2 个回答

3

在表单中,你可以有一个隐藏的ID字段。在编辑表单的时候,这个ID会和表单一起提交。而在添加表单的时候,你可以在请求中设置这个ID,比如:

formData =  req.POST.copy()
formData['id'] = getNewID()

然后把这些表单数据传递给表单。

116

如果你是从一个模型表单(ModelForm)扩展你的表单,记得使用 instance 这个参数。这里我们根据是要编辑一个已有的文章还是添加一篇新文章,传入一个已有的 instance 或者一个新的。在这两种情况下,author 字段都会被设置在这个实例上,所以不需要使用 commit=False。另外,我假设只有作者自己可以编辑自己的文章,因此会返回一个 HttpResponseForbidden 的响应。

from django.http import HttpResponseForbidden
from django.shortcuts import get_object_or_404, redirect, render, reverse


@login_required
def edit(request, id=None, template_name='article_edit_template.html'):
    if id:
        article = get_object_or_404(Article, pk=id)
        if article.author != request.user:
            return HttpResponseForbidden()
    else:
        article = Article(author=request.user)

    form = ArticleForm(request.POST or None, instance=article)
    if request.POST and form.is_valid():
        form.save()

        # Save was successful, so redirect to another page
        redirect_url = reverse(article_save_success)
        return redirect(redirect_url)

    return render(request, template_name, {
        'form': form
    })

在你的 urls.py 文件中:

(r'^article/new/$', views.edit, {}, 'article_new'),
(r'^article/edit/(?P<id>\d+)/$', views.edit, {}, 'article_edit'),

同一个 edit 视图可以用于添加和编辑,但只有编辑的 URL 模式会传递一个 ID 给视图。为了让这个和你的表单配合得更好,你需要在表单中去掉 author 字段:

class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article
        exclude = ('author',)

撰写回答