Django按author过滤条目报错Field 'id' expected a number 求助
问题根源
报错核心原因是index视图里author = DiaryEntry.author拿到的不是实际用户对象,是模型层的外键字段描述符(也就是报错信息里提到的ForwardManyToOneDescriptor对象)。ORM执行filter时要求外键参数传实际的用户实例/用户ID,传入字段描述符自然会触发类型不匹配错误。
另外现有代码还有两个隐藏问题:一是详情视图没做权限校验,用户只要知道条目ID就能查看其他人的日记,存在越权风险;二是所有和用户数据相关的视图没加登录限制,未登录状态访问会触发额外报错。
修复方案
1. 修正首页视图过滤逻辑
从请求对象request中获取当前登录用户作为过滤条件,同时加上登录校验:
# 先导入登录校验装饰器 from django.contrib.auth.decorators import login_required from django.shortcuts import render from .models import DiaryEntry from django.views import generic from django.views.generic.edit import CreateView # 导入类视图用的登录校验mixin from django.contrib.auth.mixins import LoginRequiredMixin @login_required def index(request): """View function for MyDiary.""" # 直接用当前登录用户作为过滤条件 diary_entry = DiaryEntry.objects.filter(author=request.user).order_by('-created_on') context = { "diary_entry": diary_entry, } return render(request, 'diary_index.html', context=context)
2. 修复详情视图的越权漏洞
你原来写的get_data是不存在的方法,Django通用视图的上下文获取方法是get_context_data,这里直接重写查询集限制只能访问自己的条目,同时加上登录校验:
class EntryDetailView(LoginRequiredMixin, generic.DetailView): model = DiaryEntry def get_queryset(self): # 强制查询范围限定为当前用户自己创建的条目 return super().get_queryset().filter(author=self.request.user)
3. 补全创建视图的登录限制
给创建视图加上登录校验mixin,避免未登录用户访问报错:
class EntryCreate(LoginRequiredMixin, CreateView): model = DiaryEntry fields = ['title', 'content'] def form_valid(self, form): form.instance.author = self.request.user return super().form_valid(form)
配置注意
记得在项目settings.py中补充两个配置:
LOGIN_URL:填写你的登录页路由名,未登录用户访问受限页面时会自动跳转到这里LOGIN_REDIRECT_URL:填写日记首页路由名,用户登录成功后默认跳转到日记页
补充说明:
DiaryEntry.author是定义在模型类上的字段引用,只有通过请求上下文拿到的request.user才是当前访问者对应的真实用户实例,传入过滤条件才能正确匹配数据库中关联的作者记录。
内容的提问来源于stack exchange,提问作者AllyZ
相关产品推荐
相关产品推荐

