Django Rest Framework实现依赖关联模型的自定义只读active字段
解决方案
你不需要重写视图的list方法,通过调整查询集和序列化器即可实现需求,以下是两种可行方案:
方案1:查询集注解注入字段(最高效,推荐)
通过Django的annotate方法直接将关联的active字段注入到Notification查询结果中,一次查询即可获取所有需要的数据,无额外数据库开销:
- 调整视图的
get_queryset方法:
from django.db.models import F class NotificationViewSet(viewsets.ModelViewSet): serializer_class = serializers.NotificationSerializer model = Notification lookup_field='pk' def get_queryset(self): user = self.request.user return Notification.objects.filter( notificationuserlink__user=user ).annotate( # 直接将关联的active字段注解到Notification对象上 active=F('notificationuserlink__active') )
- 修改序列化器新增
active字段:
class NotificationSerializer(serializers.ModelSerializer): # 只读字段,承接注解注入的active值 active = serializers.BooleanField(read_only=True) class Meta: model=Notification fields=("value", "active")
方案2:SerializerMethodField实现
如果不想修改查询集,也可以通过序列化器的方法字段实现,注意要提前预加载关联数据避免N+1查询问题:
- 调整查询集添加预加载:
class NotificationViewSet(viewsets.ModelViewSet): serializer_class = serializers.NotificationSerializer model = Notification lookup_field='pk' def get_queryset(self): user = self.request.user return Notification.objects.filter( notificationuserlink__user=user ).prefetch_related('notificationuserlink_set')
- 修改序列化器:
class NotificationSerializer(serializers.ModelSerializer): active = serializers.SerializerMethodField() def get_active(self, obj): current_user = self.context['request'].user # 因为存在唯一约束,直接取唯一的关联记录即可 return obj.notificationuserlink_set.get(user=current_user).active class Meta: model=Notification fields=("value", "active")
额外优化建议
后续你可以直接在NotificationUserLink模型中添加联合唯一约束,在数据库层面保证关联关系唯一:
class NotificationUserLink(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) notification = models.ForeignKey(Notification, on_delete=models.CASCADE) active = models.BooleanField(default=True) class Meta: unique_together = ('user', 'notification')
内容的提问来源于stack exchange,提问作者Neil
相关产品推荐
相关产品推荐

