将表单字段设置为 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})
让我用一些代码来解释我的问题: 我正在编写一个简单的博客应用程序。我有一个 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}
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})