所以我在Django REST中做一个小项目,而我仍然习惯于ORM。我正在处理以下Django模型:
class Session(models.Model):
date = models.DateTimeField(default=now, blank=False)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='efforts', on_delete=models.CASCADE)
在给定特定月份的情况下,我对每个所有者的会话次数特别感兴趣。如下:
Session.objects.filter(date__gte=start, date__lt=end).values('owner').annotate(num_sessions=Count('owner')).order_by("owner")
此查询产生以下结构的结果:
(owner, count)
在序列化程序中,我想使用所有者检索用户名,以构建响应。我绝对没有运气。我的序列化器现在看起来像这样:
class SessionAggregateSerializer(serializers.ModelSerializer):
num_sessions = serializers.IntegerField(read_only=True)
owner = serializers.IntegerField(read_only=True)
class Meta:
model = Session
fields = ('id', 'owner', 'num_sessions')
有关如何处理此问题的任何建议?对于常规查询,我使用以下行来检索用户名,但这在当前设置中不再适用:
owner = serializers.ReadOnlyField(source='owner.username')
答案 0 :(得分:1)
我认为您可以使用SerializerMethodField
(documentation):
class SessionAggregateSerializer(serializers.ModelSerializer):
...
username = serializers.SerializerMethodField()
class Meta:
model = Session
fields = ('id', 'username', 'num_sessions')
def get_username(self, obj):
return obj.owner.username
class UserSerializer(serializers.ModelSerializer):
...
sessions = serializers.SerializerMethodField()
class Meta:
model = User
fields = ('id', 'username', 'sessions')
def get_sessions(self, obj):
return obj.efforts.all().count() # or obj.efforts.filter(efforts__date__gte=....).count()
答案 1 :(得分:0)
因此,使用例更加具体:
会话通过“努力”关系附加到用户。给定开始时间和结束时间,我想为用户显示一个列表,以及附加的会话数-带有开始日期和结束日期之间的日期。会话由分支进一步标识。对于用户来说是相同的,但是用户可能属于多个分支。因此,应该进一步细化计数,以将会话单独包含在出现在请求者用户对象的分支中的分支中。此外,会话计数为零的用户应省略,以保持结果简洁。
会话模型如下:
class Session(models.Model):
date = models.DateTimeField(default=now, blank=False)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='efforts', on_delete=models.CASCADE)
branch = models.ForeignKey(Branch, related_name='hour_branch', on_delete=models.CASCADE)
status = models.IntegerField(default=1, blank=False, validators=[MinValueValidator(0), MaxValueValidator(3)])
用户模型如下所示(为简洁起见,省略了各个字段)。
class User(AbstractUser):
branches = models.ManyToManyField(Branch)
上面的答案并不令人满意,因为它不允许我根据需要过滤用户计数中的会话。因此,为什么我最终使用conditional expression使用以下解决方案:
有关视图的代码:
class AggregateSessionList(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSessionsSerializer
permission_classes = (permissions.IsAdminUser,)
def get_queryset(self):
today=datetime.date.today()
month=self.request.query_params.get('month', today.month)
year=self.request.query_params.get('year', today.year)
start = datetime.date(year=year, month=month, day=1)
end = datetime.datetime(year=start.year + int(start.month / 12), month=int((start.month % 12) + 1), day=1)
branches = self.request.user.branches.all()
return User.objects.annotate(
sessions=Count(Case(
When(efforts__date__gt=start, efforts__date__lt=end, efforts__branch__in=branches, then=1),
output_field=IntegerField()))).filter(sessions__gt=0)
序列化程序的代码:
class UserSessionsSerializer(serializers.ModelSerializer):
sessions = serializers.IntegerField()
class Meta:
model = User
fields = ('username', 'sessions')
以为我会分享此解决方案,因为找不到类似的东西。
此解决方案中对ruddra的回答更受欢迎的另一个好处是,仅执行一个数据库查询。这与ruddra的答案相反,后者对每个用户执行一个附加查询(这对我的要求而言不可行)。