在 Django 的 DetailView 中将表单字段设置为对象 ID

Posted

技术标签:

【中文标题】在 Django 的 DetailView 中将表单字段设置为对象 ID【英文标题】:Setting a form field to the object id in Django's DetailView 【发布时间】:2020-11-13 09:41:13 【问题描述】:

让我用一些代码来解释我的问题: 我正在编写一个简单的博客应用程序。我有一个 Post ListView,它列出了博客帖子(显然),还有一个 DetailView,它显示了所选帖子的内容。 DetailView 使用默认关键字 object 来引用 DetailView 中显示的帖子实例。每篇博文的末尾都有一个评论部分。

forms.py 我有一个 CommentForm 类:

class CommentForm(ModelForm):
    class Meta:
        model = Comment
        fields = ['author_nickname', 'content']

在 models.py 中我有一个 Comment 模型:

class Comment(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    author_nickname = models.CharField(max_length=10)
    date_posted = models.DateTimeField(auto_now_add= True)
    content = models.TextField(max_length=90)
    post = models.ForeignKey(Post,on_delete=models.CASCADE)

我使用一个DetailView来显示选中帖子的内容,但是由于它还有一个用于将cmets添加到评论部分的表单,所以它继承自DetailView和FormView,如下所示:

class PostDetailView(DetailView, FormView):
    model = Post
    form_class = CommentForm
    success_url = '/thanks/'

    def form_valid(self, form):
        form.save()
        return super().form_valid(form)

现在,问题来了:我希望 CommentForm 向 DetailView 显示的帖子添加评论,表单所在的位置(显然)。我在 DetailView 模板的末尾添加了表单标签。它就住在这里:

<form method="POST">
    % csrf_token %
     form.as_p 
    <button type="submit" class="btn btn-primary">Add</button>
</form>

显然,当我提交此表单时,我收到一条错误消息,因为缺少 Post_id。如果我将 Post 字段添加到 forms.py 中的 CommentForm 类,如下所示:

fields = ['author_nickname', 'content', 'post']

然后手动指定帖子并点击提交,表单可以正常工作,并正确添加评论而没有错误(出于开发目的,它当前将用户导航到 /thanks/) 那么,如何在表单中指定 post_id 字段而不显示该字段?我尝试在 DetailView 模板的表单标签之间添加类似的内容:

<input type="hidden" name="post_id" value="object.id">

但它不起作用,我仍然得到错误:

NOT NULL 约束失败:blog_comment.post_id

谁能帮帮我? :(我的手被绑了:c 我不知道如何解决这个问题。我不知道如何访问 views.py 中的对象实例,因此设置初始字段值对我没有帮助。

请帮忙:

【问题讨论】:

【参考方案1】:

最好将其设为CreateView [Django-doc],然后自己将Post 对象传递给上下文,例如:

from django.shortcuts import get_object_or_404

class PostDetailView(CreateView):
    model = Comment
    form_class = CommentForm
    success_url = '/thanks/'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        obj = get_object_or_404(Post, pk=self.kwargs['pk'])
        context['object'] = context['post'] = obj
        return context

    def form_valid(self, form):
        form.instance.post_id = self.kwargs['pk']
        return super().form_valid(form)

在这里,如果表单有效,我们将post_id设置为URL中传递的pk,然后让CreateView进一步处理逻辑。这将保存表单,并重定向到success_url

【讨论】:

【参考方案2】:

我创造了这样的东西:

from django.views.generic.edit import FormMixin

class PostDetailView(FormMixin, DetailView):
    model = Post
    template_name = 'blog/post_detail.html'
    context_object_name = 'post'
    form_class = CommentForm

在 get_context_data 中,我初始化表单,并在其中指出 initial='post': self.object 的帖子

def get_context_data(self, **kwargs):
    context = super(PostDetailView, self).get_context_data(**kwargs)
    context['form'] = CommentForm(initial='post': self.object)
    return context

def post(self, request, *args, **kwargs):
    self.object = self.get_object()
    form = self.get_form()
    if form.is_valid():
        return self.form_valid(form)
    else:
        return self.form_invalid(form)

def form_valid(self, form):
    form.instance.author = self.request.user
    form.instance.post = self.get_object()
    form.save()
    return super(PostDetailView, self).form_valid(form)

def get_success_url(self):
    return reverse('post_detail', kwargs='slug': self.object.slug)

【讨论】:

以上是关于在 Django 的 DetailView 中将表单字段设置为对象 ID的主要内容,如果未能解决你的问题,请参考以下文章

在 splitviewcontroller 中将数组从 masterview 发送到 detailview

Django - DetailView 中的 DateTimeField

Django:在通用 DetailView 中实现表单

Django - 使用 DetailView 创建视图

Django 通用视图:何时使用 ListView 与 DetailView

Django DetailView 动态模型