如何自动将评论关联至对应帖子?Django开发问题求助
问题
我有一个创建评论的表单,该表单已能确定评论所属的用户,但无法将评论关联至其对应的帖子。执行时出现错误:/addcom路径下发生ValueError:无法赋值"1":"Comments.connect_post"必须是"Post"的实例。
相关代码如下:
models.py
class Post(models.Model): title = models.CharField(max_length=150) text = models.CharField(max_length=8000) data = models.DateTimeField(auto_now_add=True) image = models.ImageField(upload_to='media/', null=True, blank=True) user = models.ForeignKey(User, on_delete=models.CASCADE) connect_category = models.ManyToManyField('Category') def __str__(self): return self.title def save(self): super().save() if self.image: img = Image.open(self.image.path) if img.height > 300 or img.width > 300: new_img = (500, 600) img.thumbnail(new_img) img.save(self.image.path) def get_absolute_url(self): return reverse('post', args=[str(self.id)]) class Category(models.Model): title = models.CharField(max_length=30) class Comments(models.Model): author = models.ForeignKey(User, on_delete=models.CASCADE) text = models.CharField(max_length=800) approved = 'Approved' refused = 'Refused' choice = ( (approved, 'Одобрено'), (refused, 'Отказано') ) status = models.CharField(max_length=8, choices=choice, default='Ожидание') connect_post = models.ForeignKey('Post', on_delete=models.CASCADE, null=True) def get_absolute_url(self): return reverse('post', args=[str(self.id)])
views.py
class PostDetail(DetailView): model = Post template_name = 'post.html' context_object_name = 'post' form_class = CommentForm success_url = '' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['comment_form'] = CommentForm(initial={'connect_post': self.object.id}) return context class CommentCreateView(CreateView): form_class = CommentForm success_url = '/' model = Comments def form_valid(self, form): form.instance.author = self.request.user post_id = form.cleaned_data['connect_post'] form.instance.connect_post = post_id return super().form_valid(form)
forms.py
class CommentForm(forms.ModelForm): connect_post = forms.IntegerField(widget=forms.HiddenInput) class Meta: model = Comments fields = { 'text', } exclude = ['author', 'connect_post']
urls.py
urlpatterns = [ path('', PostList.as_view(), name='news'), path('post/<int:pk>', PostDetail.as_view(), name='post'), path('create/', PostCreate.as_view(), name='post_create'), path('<int:pk>/edit/', PostEdit.as_view(), name='post_edit'), path('profile/', Profile, name='profile'), path('addcom', CommentCreateView.as_view(), name='comment_create'), path('usercomments/', user_comments, name="usercomments"), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
解决方案
错误核心是:connect_post是外键字段,必须赋值Post模型实例,而不是单纯的ID数字。下面提供两种可行的修改方案:
方案一:保留隐藏字段,转换ID为实例
直接修改CommentCreateView的form_valid方法,将获取到的post_id转换为Post实例:
from django.shortcuts import get_object_or_404 class CommentCreateView(CreateView): form_class = CommentForm success_url = '/' model = Comments def form_valid(self, form): form.instance.author = self.request.user # 获取Post实例,用get_object_or_404避免ID不存在的错误 post_id = form.cleaned_data['connect_post'] form.instance.connect_post = get_object_or_404(Post, id=post_id) return super().form_valid(form)
方案二:绑定URL与帖子ID(更安全规范)
这种方式不需要在表单中传递隐藏字段,直接从URL参数获取帖子ID,更安全且逻辑清晰:
1. 修改urls.py
将评论创建的URL与帖子ID绑定:
urlpatterns = [ # ... 其他路径不变 path('post/<int:pk>/addcom/', CommentCreateView.as_view(), name='comment_create'), # ... ]
2. 修改CommentCreateView
从URL的pk参数获取帖子ID,直接关联实例:
from django.shortcuts import get_object_or_404 class CommentCreateView(CreateView): form_class = CommentForm success_url = '/' model = Comments def form_valid(self, form): form.instance.author = self.request.user # 从URL参数获取帖子ID并关联实例 form.instance.connect_post = get_object_or_404(Post, id=self.kwargs['pk']) return super().form_valid(form)
3. 简化forms.py
删除多余的connect_post字段定义:
class CommentForm(forms.ModelForm): class Meta: model = Comments fields = ['text'] exclude = ['author', 'connect_post']
4. 修改PostDetail的表单初始化
不需要再传递initial参数:
class PostDetail(DetailView): # ... 其他属性不变 def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['comment_form'] = CommentForm() return context
5. 调整模板中的表单提交路径
确保表单提交到绑定帖子ID的URL:
<form action="{% url 'comment_create' post.id %}" method="post"> {% csrf_token %} {{ comment_form.as_p }} <button type="submit">提交评论</button> </form>
内容的提问来源于stack exchange,提问作者MeRKaLyuT
相关产品推荐
相关产品推荐

