重写Django UpdateView的get()方法时出现'str'对象没有属性'get'的错误
解决Django UpdateView中返回字符串导致的AttributeError问题
错误原因分析
你遇到的'str' object has no attribute 'get'错误,核心原因是你在get()方法的else分支返回了一个字符串:reverse()函数返回的是URL路径的字符串形式,而Django视图的请求处理方法必须返回一个HttpResponse类的对象(比如HttpResponseRedirect、TemplateResponse等)。中间件在处理响应时,试图对这个字符串调用get()方法(比如检查X-Frame-Options头),自然就会报错。
另外,只重写get()方法来做权限校验是不完整的——用户可以直接构造POST请求绕过这个限制,修改不属于自己的Stats数据。
正确的解决方案:重写get_object()方法(推荐)
Django的基于类的视图(CBV)提供了get_object()方法,专门用来获取当前视图要操作的对象。重写这个方法是实现对象级权限控制的标准做法,既能限制GET请求,也能限制POST请求。
方案1:利用OneToOne关联特性(无需URL中的pk参数)
因为Stats和User是OneToOne关联,每个用户只有一个Stats对象,所以URL里不需要pk参数,直接通过当前用户获取即可:
from django.http import Http404 from django.views.generic.edit import UpdateView from .models import Stats class StatsUpdateView(UpdateView): model = Stats fields = ('stat1', 'stat2', 'stat3') def get_object(self, queryset=None): # 获取当前登录用户关联的Stats对象 try: obj = self.request.user.stats except Stats.DoesNotExist: # 处理用户没有Stats记录的情况,比如返回404或重定向 raise Http404("你还没有关联的统计数据") return obj
对应的URL配置可以简化为:
path('updatestats/', StatsUpdateView.as_view(), name='updatestats')
方案2:保留URL中的pk参数(如果有特殊需求)
如果你必须保留URL里的pk参数,重写get_object()时需要检查对象是否属于当前用户:
from django.core.exceptions import PermissionDenied from django.views.generic.edit import UpdateView from .models import Stats class StatsUpdateView(UpdateView): model = Stats fields = ('stat1', 'stat2', 'stat3') def get_object(self, queryset=None): # 先调用父类方法获取对应pk的对象 obj = super().get_object(queryset=queryset) # 校验对象所属用户 if obj.user != self.request.user: # 可以重定向到首页,或者抛出403禁止访问错误 # return redirect('homepage:home') raise PermissionDenied("你没有权限修改这条数据") return obj
如果你坚持要重写get()方法(不推荐)
如果一定要通过重写get()方法实现,需要返回正确的HttpResponse对象,而不是字符串。可以调用父类的get()方法来获取正常的响应,或者用redirect()(它返回的是HttpResponseRedirect对象):
def get(self, *args, **kwargs): stats_obj = Stats.objects.get(pk=kwargs['pk']) if self.request.user != stats_obj.user: return redirect('homepage:home') else: # 调用父类的get方法,返回合法的HttpResponse对象 return super().get(*args, **kwargs)
额外提示
- 永远优先使用Django CBV提供的标准钩子方法(比如
get_object()、get_queryset())来做权限控制,这样代码更符合框架规范,也能覆盖所有请求方法。 - 可以结合Django的
@login_required装饰器或者LoginRequiredMixin确保只有登录用户能访问这个视图。
内容的提问来源于stack exchange,提问作者CCima
相关产品推荐
相关产品推荐

