Django Rest如何实现仅展示登录作者关联博客的评论?
场景描述
作者Jhone发布了标题为*"This blog written by author Jhone"的博客,作者Joe发布了标题为"This blog written by author Joe"*的博客。Jhone的博客收到20条评论,Joe的博客收到10条评论。需求是:Jhone登录后只能查看自己博客的评论,Joe同理。
问题现状
尝试使用查询语句Comment.objects.all().filter(blog__author=request.user.id),但API仍允许所有用户查看彼此博客的评论。
问题排查与解决方案
1. 模型字段语法错误(核心问题)
查看你的models.py中Comment模型的代码:
class Comment(models.Model): name = models.CharField(max_length=100) email = models.EmailField(max_length=100) comment = models.TextField() blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
blog字段的定义前多了一个空格,导致字段名实际是 blog(带前导空格)。这会导致Django ORM无法识别blog字段,你写的filter(blog__author=...)条件会被忽略,最终返回所有评论。
修复方法:删除blog字段前的空格,修正为:
class Comment(models.Model): name = models.CharField(max_length=100) email = models.EmailField(max_length=100) comment = models.TextField() blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
2. 完善认证与权限控制
即使修复了字段问题,如果没有配置认证和权限,未登录用户或任意用户仍可能访问接口,导致逻辑失效。
步骤1:配置全局认证与权限
在项目的settings.py中添加DRF配置:
REST_FRAMEWORK = { # 配置认证方式,确保request.user是当前登录用户 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.BasicAuthentication', ], # 配置默认权限,仅允许登录用户访问接口 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', ] }
步骤2:在视图中添加权限装饰器
在comment_api视图上添加权限装饰器,确保只有登录用户能访问:
from rest_framework.permissions import IsAuthenticated from rest_framework.decorators import permission_classes @api_view(['POST', 'GET']) @permission_classes([IsAuthenticated]) # 添加这行 def comment_api(request): # 原视图代码...
3. 优化查询语句
将查询语句中的request.user.id改为直接使用request.user,更符合Django ORM的使用习惯,也能避免潜在的用户ID匹配问题:
comment = Comment.objects.filter(blog__author=request.user)
(all()可以省略,因为filter()本身会返回查询集)
4. 补充POST请求的权限校验(可选)
当前POST请求允许任意登录用户创建评论到任意博客,如果你需要限制用户只能给自己的博客创建评论,可以在保存时校验:
if request.method == 'POST': serializer = CommentSerializer(data=request.data) if serializer.is_valid(): # 校验评论关联的博客是否属于当前用户 blog = serializer.validated_data['blog'] if blog.author != request.user: return Response({"error": "你只能给自己的博客添加评论"}, status=status.HTTP_403_FORBIDDEN) serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
内容的提问来源于stack exchange,提问作者boyenec

