Django中DeferredAttribute与int相加的TypeError问题排查与解决
错误成因
- 混淆了模型类和模型实例的用法:代码中
watchlist是你的模型类名,watchlist.number_ratings调用的是模型的字段定义(DeferredAttribute类型),而非从数据库取出的具体实例的数值,因此无法和整数1执行加法操作。你实际应该操作的是通过watchlist.objects.get(pk=pk)获取的实例watchlist_movie。
解决方法
修改代码中所有错误引用watchlist.xxx的地方,替换为实例watchlist_movie.xxx,修正后的perform_create方法代码如下:
def perform_create(self, serializer): pk = self.kwargs.get('pk') watchlist_movie = watchlist.objects.get(pk=pk) review_user = self.request.user review_queryset = Review.objects.filter(watchlist=watchlist_movie, review_user=review_user) if review_queryset.exists(): raise ValidationError('You have already reviewed this movie.') if watchlist_movie.number_ratings == 0: watchlist_movie.avg_rating = serializer.validated_data['rating'] else: watchlist_movie.avg_rating = (watchlist_movie.avg_rating + serializer.validated_data['rating']) / 2 watchlist_movie.number_ratings = watchlist_movie.number_ratings + 1 watchlist_movie.save() serializer.save(watchlist = watchlist_movie, review_user = review_user)
另外,推荐使用Django的F()表达式实现原子更新,避免并发场景下的统计错误,将数值更新代码替换为:
from django.db.models import F watchlist_movie.number_ratings = F('number_ratings') + 1
该方式会直接在数据库层面执行更新操作,不会出现多用户同时操作时的数值覆盖问题。
未来避免这类错误的建议
- 严格区分模型类和模型实例:模型类是数据表的抽象定义,实例才对应数据库中的具体数据行,操作字段值必须使用实例。
- 调试时打印变量类型:遇到类型错误时,用
print(type(变量名))确认变量类型,快速定位是类属性还是实例属性。 - 数值更新场景优先用
F()表达式:既避免类型错误,也能保证并发操作的原子性。
内容的提问来源于stack exchange,提问作者Rohit Gajula
相关产品推荐
相关产品推荐

