Django提交评论报错:PostDetail.post()收到多个slug参数
Django提交评论触发TypeError问题解决
提交博客评论时出现报错:TypeError: PostDetail.post() got multiple values for argument 'slug',预期流程是评论提交后进入审核,通过后展示。
报错回溯
Environment: Request Method: POST Request URL: http://127.0.0.1:8000/blog/cubs/post/should-be-the-final-test-lmao/ Django Version: 4.1.2 Python Version: 3.10.6 Installed Applications: ['beavers.apps.BeaversConfig', 'cubs.apps.CubsConfig', 'scouts.apps.ScoutsConfig', 'accounts.apps.AccountsConfig', 'executive.apps.ExecutiveConfig', 'main_website.apps.MainWebsiteConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.sites', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.sitemaps', 'django.contrib.staticfiles', 'django_summernote', 'crispy_bootstrap5', 'taggit_helpers', 'taggit_labels', 'debug_toolbar', 'admin_reorder', 'crispy_forms', 'storages', 'taggit'] Installed Middleware: ('whitenoise.middleware.WhiteNoiseMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'debug_toolbar.middleware.DebugToolbarMiddleware', 'admin_reorder.middleware.ModelAdminReorder') Traceback (most recent call last): File "/home/kiza054/.local/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner response = get_response(request) File "/home/kiza054/.local/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/home/kiza054/.local/lib/python3.10/site-packages/django/views/generic/base.py", line 103, in view return self.dispatch(request, *args, **kwargs) File "/home/kiza054/.local/lib/python3.10/site-packages/django/contrib/auth/mixins.py", line 73, in dispatch return super().dispatch(request, *args, **kwargs) File "/home/kiza054/.local/lib/python3.10/site-packages/django/views/generic/base.py", line 142, in dispatch return handler(request, *args, **kwargs) Exception Type: TypeError at /blog/cubs/post/should-be-the-final-test-lmao/ Exception Value: PostDetail.post() got multiple values for argument 'slug'
相关代码
PostDetail视图(views.py)
class PostDetail(LoginRequiredMixin, DetailView): model = Post form_class = CommentForm template_name = "cubs/post_detail.html" def get_form(self): form = self.form_class(instance=self.object) return form def post(self, slug, *args, **kwargs): new_comment = None pk = self.kwargs.get('pk') post = get_object_or_404(Post, pk=pk) form = CommentForm(request.POST) if form.is_valid(): # Create new_comment object but don't save to the database yet new_comment = form.save(commit=False) # Assign the current post to the comment new_comment.post = post # Save the comment to the database new_comment.save() messages.warning(request, "Your comment is awaiting moderation, once moderated it will be published") return redirect('cubs_blog_post_detail', slug=slug) else: return render(request, self.template_name, {'form': form}) def get_context_data(self, *args, **kwargs): slug = self.kwargs.get('slug') context = super().get_context_data(**kwargs) post = get_object_or_404(Post, slug=slug) comments = post.cubs_blog_comments.filter(active=True).order_by('-date_posted') articles = Article.objects.filter(status=1).order_by('-date_posted')[:2] post_likes = get_object_or_404(Post, slug=self.kwargs['slug']) total_likes = post_likes.total_likes() if post_likes.likes.filter(id=self.request.user.id).exists(): liked = True else: liked = False context['liked'] = liked context['articles'] = articles context['comments'] = comments context['total_likes'] = total_likes context['title'] = 'Post Details' context.update({ 'comment_form': self.get_form(), }) return context
Comment模型(models.py)
class Comment(models.Model): post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='cubs_blog_comments') name = models.CharField(max_length=80) email = models.EmailField() comment = models.TextField() date_posted = models.DateTimeField(auto_now_add=True) active = models.BooleanField(default=False) class Meta: ordering = ['date_posted'] def __str__(self): return 'Comment {} by {}'.format(self.comment, self.name)
Post模型(models.py)
class Post(models.Model): class Status(models.IntegerChoices): Draft = 0 Published = 1 title = models.CharField(max_length=200, unique=True) slug = models.SlugField(max_length=200, unique=True) author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='cubs_blog_posts') updated_on = models.DateTimeField(auto_now=True) content = models.TextField() date_posted = models.DateTimeField(auto_now_add=True) status = models.IntegerField(choices=Status.choices, default=Status.Draft) likes = models.ManyToManyField(User, related_name="cubs_blog_posts_likes") class Meta: ordering = ['-date_posted'] def __str__(self): return self.title def total_likes(self): return self.likes.count() def get_absolute_url(self): return reverse("cubs_blog_post_detail", kwargs={"slug": str(self.slug)}) def save(self, *args, **kwargs): self.slug = slugify(self.title) super(Post, self).save(*args, **kwargs)
错误原因及修复方案
1. Post方法签名错误(核心问题)
Django类视图的post方法必须以request作为self之后的第一个参数,当前签名def post(self, slug, *args, **kwargs):会导致request被错误赋值给slug,同时路由传递的slug又通过kwargs传入,最终引发重复传参错误。
2. 冗余的Post查询
DetailView已经通过slug获取了当前Post对象并存储在self.object中,无需再通过pk或slug重复查询。
3. 未正确使用视图的request属性
代码中直接使用request而非self.request,会导致未定义错误。
修正后的PostDetail视图
class PostDetail(LoginRequiredMixin, DetailView): model = Post form_class = CommentForm template_name = "cubs/post_detail.html" # 显式声明用slug作为查询字段,替代默认的pk slug_field = 'slug' slug_url_kwarg = 'slug' def get_form(self): # 评论表单无需绑定Post实例,直接创建空表单即可 return self.form_class() def post(self, request, *args, **kwargs): new_comment = None # 直接使用DetailView已获取的Post对象 post = self.get_object() form = self.form_class(request.POST) if form.is_valid(): new_comment = form.save(commit=False) new_comment.post = post # 自动填充当前登录用户的姓名和邮箱,避免重复输入 new_comment.name = request.user.get_full_name() new_comment.email = request.user.email new_comment.save() messages.warning(request, "你的评论正在等待审核,通过后将展示") # 使用Post模型的get_absolute_url跳转,更灵活易维护 return redirect(post.get_absolute_url()) else: # 获取上下文并传递错误表单,保留页面原有状态 context = self.get_context_data() context['comment_form'] = form return render(request, self.template_name, context) def get_context_data(self, *args, **kwargs): context = super().get_context_data(**kwargs) post = self.object comments = post.cubs_blog_comments.filter(active=True).order_by('-date_posted') articles = Article.objects.filter(status=1).order_by('-date_posted')[:2] total_likes = post.total_likes() liked = post.likes.filter(id=self.request.user.id).exists() context['liked'] = liked context['articles'] = articles context['comments'] = comments context['total_likes'] = total_likes context['title'] = '文章详情' context['comment_form'] = self.get_form() return context
额外优化建议
- 给CommentForm添加验证规则,拦截空评论或无效邮箱
- 在Comment模型中添加
user外键关联登录用户,方便评论管理与溯源
内容的提问来源于stack exchange,提问作者Kiran Sarda
相关产品推荐
相关产品推荐

