django - Django REST按日期序列化字段组
问题描述
问题:无法按日期对 JSON 输出进行分组
本文底部的解决方案
我正在序列化一个模型并得到这个输出:
[
{
"date": "2020-11-24",
"name": "Chest",
"workout": {
"name": "Chest",
"exercise": 1,
"repetitions": 10,
"weight": 80
}
},
{
"date": "2020-11-24",
"name": "Chest",
"workout": {
"name": "Chest",
"exercise": 1,
"repetitions": 10,
"weight": 85
}
},
{
"date": "2020-11-24",
"name": "Chest",
"workout": {
"name": "Chest",
"exercise": 1,
"repetitions": 10,
"weight": 90
}
},
我想像下面的 JSON 一样获取它并按date分组。
[
{
"date": "2020-11-24",
"workout": {
"name": "Chest",
"exercise": 1,
"repetitions": 10,
"weight": 80
},
"name": "Chest",
"exercise": 1,
"repetitions": 10,
"weight": 85
},
"name": "Chest",
"exercise": 1,
"repetitions": 10,
"weight": 90
},
}
]
我有一个模型:
class WorkoutLog(models.Model):
date = models.DateField()
name = models.CharField(max_length=50) #When save() name = Workout.name
exercise = models.ForeignKey('Exercise', related_name='log', on_delete=models.CASCADE)
repetitions = models.IntegerField()
weight = models.IntegerField()
尝试按日期对 JSON 进行序列化和分组:
class WorkoutLogSerializer(serializers.ModelSerializer):
class Meta:
model = WorkoutLog
fields = ['date', 'workout']
workout = serializers.SerializerMethodField('get_workout')
def get_workout(self, obj):
return {
'name': obj.name,
'exercise': obj.exercise_id,
'repetitions': obj.repetitions,
'weight': obj.weight,
}
该代码允许我自定义字段布局,但不能真正按日期对其进行分组。您对如何构建它有什么建议吗?
非常感谢大家的帮助!
如果需要,这是我的 view.py
def workout_log(request):
if request.method == 'GET':
workout_log = WorkoutLog.objects.all()
serializer = WorkoutLogSerializer(workout_log, many=True)
return JsonResponse(serializer.data, safe=False)
Mahmoud Adel 的解决方案:
视图.py
def workout_log(request):
if request.method == 'GET':
workout_log = WorkoutLog.objects.order_by('date').values('date').distinct()
serializer = WorkoutLogSerializer(workout_log, many=True)
return JsonResponse(serializer.data, safe=False)
序列化程序.py
class WorkoutFieldSerializer(serializers.Serializer):
name = serializers.CharField()
#exercise = serializers.IntegerField()
repetitions = serializers.IntegerField()
weight = serializers.IntegerField()
class WorkoutLogSerializer(serializers.ModelSerializer):
class Meta:
model = WorkoutLog
fields = ['date', 'workout']
workout = serializers.SerializerMethodField('get_workout')
def get_workout(self, obj):
workouts = WorkoutLog.objects.filter(date=obj['date'])
workout_serializer = WorkoutFieldSerializer(workouts, many=True)
return workout_serializer.data
解决方案
你可以做这样的事情
让我们首先从您的观点开始,我将像这样调整查询集
def workout_log(request):
if request.method == 'GET':
workout_log = WorkoutLog.objects.order_by('date').distinct('date').only('date')
serializer = WorkoutLogSerializer(workout_log, many=True)
return JsonResponse(serializer.data, safe=False)
然后在你的WorkoutLogSerializer
class WorkoutLogSerializer(serializers.ModelSerializer):
class Meta:
model = WorkoutLog
fields = ['date', 'workout']
workout = serializers.SerializerMethodField('get_workout')
def get_workout(self, obj):
workouts = WorkoutLog.objects.filter(date=obj.date)
workout_serializer = WorkoutSerializer(workouts, many=True)
return workout_serializer.data
最后,创建WorkoutSerializer
class WorkoutSerializer(serializers.Serializers):
name = serializers.CharField()
exercise = serializers.IntegerField()
repetitions = serializers.IntegerField()
weight = serializers.IntegerField()
前面的方法首先会到数据库中获取distinct
日期,然后WorkoutLogSerializer
将使用每个日期来选择具有它的相应对象,然后我们序列化这些对象。
我们这样做得到了预期的结果,请注意,这将导致,2 DB hits
可能有另一种方法可以在一个 DB 命中中做到这一点,如果我想通了,我会更新我的答案
注意:我写这篇文章是为了解释我没有运行它的流程和逻辑,虽然它应该可以工作,但我可能会忘记一些会显示错误的内容,请随时尝试。
更新:如果您使用 SQLite,请检查此答案评论。
推荐阅读
- javascript - 对象数组比较 2 个元素值
- c# - 2 SQL Server 中的 GridControl 和链接表
- ansible - 无法对 Ansible 需要创建的临时文件设置权限
- reactjs - React ant design 仅重置一个输入字段
- linux - Snap 和 certbot,未知命令“未设置”
- python-3.x - Python 3:如何将列表中的元素添加为字典的值?
- django - csrf_exempt 设置但 CSRF 失败:Referer 检查失败 - 没有Referer
- python - 如何创建 login_required 函数
- c# - 是否可以使用 protobuf-net 为扩展名为“FieldOptions”的 proto2 文件生成 C# 文件?
- google-apps-script - 在每张纸上隐藏和显示行