Django 3.2中如何关联Profile与Rating模型返回带评分的列表
解决方案:在Django中关联Profile与Rating模型并返回带评分的列表
针对你的需求,有两种常见实现方式,分别对应「返回平均评分」和「返回所有关联评分」的场景,以下是具体操作:
一、为每个Profile添加平均评分(推荐用于展示整体评分)
1. 修改查询集,计算平均评分
在profiles/views.py中,导入聚合函数并修改查询集,过滤掉已删除的评分后计算平均星级:
from django.db.models import Avg, Q # ... 其他代码保持不变 profiles_queryset = Profile.objects.nearby_ground_list(coordinates).annotate( # 计算有效评分的平均值,is_remove=False过滤已删除的评分 average_rating=Avg('rating__stars', filter=Q(rating__is_remove=False)) )
2. 更新序列化器,添加平均评分字段
在profiles/serializers.py中,为ProfileSerializer新增average_rating字段:
from rest_framework import serializers from .models import Profile class ProfileSerializer(serializers.ModelSerializer): # 只读字段,对应查询集annotate的结果,默认值避免无评分时返回null average_rating = serializers.FloatField(read_only=True, default=0.0) class Meta: model = Profile # 列出你需要返回的Profile字段,加上average_rating fields = ['id', 'name', 'owner', 'is_premium', 'average_rating']
二、返回每个Profile的所有关联评分
如果你需要展示所有用户对该Profile的评分列表,可以用预加载关联数据的方式避免N+1查询问题:
1. 优化查询集,预加载有效评分
在profiles/views.py中,导入Prefetch并修改查询集:
from django.db.models import Prefetch from ratings.models import Rating # ... 其他代码保持不变 profiles_queryset = Profile.objects.nearby_ground_list(coordinates).prefetch_related( # 预加载未删除的评分,并将结果存到valid_ratings属性中 Prefetch('rating_set', queryset=Rating.objects.filter(is_remove=False), to_attr='valid_ratings') )
2. 嵌套序列化器,返回评分列表
在profiles/serializers.py中,定义评分序列化器并嵌套到Profile序列化器中:
from rest_framework import serializers from .models import Profile from ratings.models import Rating class RatingSerializer(serializers.ModelSerializer): class Meta: model = Rating fields = ['user', 'stars', 'create_time'] class ProfileSerializer(serializers.ModelSerializer): # 嵌套评分序列化器,many=True表示多个评分 valid_ratings = RatingSerializer(many=True, read_only=True) class Meta: model = Profile fields = ['id', 'name', 'owner', 'is_premium', 'valid_ratings']
额外优化建议
为了让反向关联更直观,建议修改ratings/models.py中的外键字段,添加related_name:
profile = models.ForeignKey(Profile, verbose_name=_(\"profile\"), on_delete=models.CASCADE, related_name='ratings')
之后你就可以用profile.ratings代替默认的profile.rating_set,代码可读性更强。
注意点
- 你的现有代码中,GET请求使用
request.data获取参数是错误的,GET请求参数应该用request.query_params,否则无法正确获取到coordinates参数。 - 代码中
kind变量未定义,需要补充定义或移除相关代码。
内容的提问来源于stack exchange,提问作者Ahmed Yasin
相关产品推荐
相关产品推荐

