如何在DRF中为Bartender模型添加获取当前用户Rating的方法
解决方法:在DRF中获取当前用户对Bartender的Rating
这个问题其实是Django/DRF分层设计里的常见误区——模型层本身是和请求上下文完全隔离的,self在模型方法里指代的是模型实例,和当前请求的用户、请求对象没有任何关联,所以没法直接在Bartender模型里写方法来拿到当前用户的Rating。
正确的做法是把这个逻辑放到序列化器或者ViewSet里,因为这两层可以直接访问到请求上下文。下面给你两种常用的实现方式:
前提假设
先明确你的模型结构(如果和这个不一致,你可以调整代码适配):
from django.contrib.auth.models import User from django.db import models class Bartender(models.Model): name = models.CharField(max_length=100) # 其他自定义字段... class Rating(models.Model): bartender = models.ForeignKey(Bartender, on_delete=models.CASCADE, related_name='ratings') user = models.ForeignKey(User, on_delete=models.CASCADE) score = models.IntegerField() # 其他评分相关字段...
方式一:在序列化器中添加自定义字段
这是最常用的方式,适合在返回Bartender详情/列表时,同时带上当前用户的评分:
from rest_framework import serializers class RatingSerializer(serializers.ModelSerializer): class Meta: model = Rating fields = ['id', 'score'] class BartenderSerializer(serializers.ModelSerializer): # 自定义字段,用来返回当前用户的评分 current_user_rating = serializers.SerializerMethodField() class Meta: model = Bartender fields = ['id', 'name', 'current_user_rating'] def get_current_user_rating(self, obj): # 从序列化器的context中获取request对象(DRF默认会传入) request = self.context.get('request') # 先判断用户是否登录 if request and request.user.is_authenticated: # 通过related_name查询当前用户对这个Bartender的评分 rating = obj.ratings.filter(user=request.user).first() if rating: # 用RatingSerializer序列化评分数据,或者直接返回字典 return RatingSerializer(rating).data # 如果用户未登录或没有评分,返回None或空字典 return None
然后在你的ViewSet中直接使用这个序列化器即可(DRF的ModelViewSet会自动把request传入序列化器的context):
from rest_framework import viewsets class BartenderViewSet(viewsets.ModelViewSet): queryset = Bartender.objects.all() serializer_class = BartenderSerializer
方式二:在ViewSet中自定义Action
如果你需要单独提供一个接口来获取某个Bartender的当前用户评分,可以用DRF的自定义Action:
from rest_framework.decorators import action from rest_framework.response import Response from rest_framework import status class BartenderViewSet(viewsets.ModelViewSet): queryset = Bartender.objects.all() serializer_class = BartenderSerializer # 自定义一个detail=True的action,意味着需要传入Bartender的pk @action(detail=True, methods=['get']) def current_user_rating(self, request, pk=None): bartender = self.get_object() if not request.user.is_authenticated: return Response({'detail': '请先登录'}, status=status.HTTP_401_UNAUTHORIZED) rating = bartender.ratings.filter(user=request.user).first() if rating: return Response(RatingSerializer(rating).data) else: return Response({'detail': '当前用户未对该调酒师评分'}, status=status.HTTP_404_NOT_FOUND)
这个方式会生成一个类似/api/bartenders/{pk}/current_user_rating/的接口,专门返回当前用户对指定Bartender的评分。
为什么不推荐在模型里实现?
Django的MTV设计模式中,模型层负责数据逻辑(比如数据验证、数据库操作),而请求上下文属于视图层的职责。把请求相关的逻辑放到模型里会导致:
- 模型和请求上下文耦合,难以单独测试模型
- 违背单一职责原则,模型变得臃肿
- 无法在非请求场景下复用这个逻辑(比如后台脚本、管理命令)
内容的提问来源于stack exchange,提问作者Shezan Kazi
相关产品推荐
相关产品推荐

