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

Setting a form field to the object id in Django's DetailView

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

forms.py 我有一个 CommentForm class:

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来显示选中的内容post,但是由于它还有一个用于在评论区添加评论的表单,所以它继承自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 显示的 post 添加评论,表单所在的位置(显然).我在 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 class 中,如下所示:

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

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

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

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

NOT NULL constraint failed: blog_comment.post_id

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

请帮忙:<

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

from django.shortcuts import <b>get_object_or_404</b>

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, <b>pk=self.kwargs['pk']</b>)
        context['object'] = context['post'] = obj
        return context

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

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

我创建了这样的东西:

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}

指示 post
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})