Django REST 按日期序列化字段组

Django REST serialize field group by date

问题:无法按日期

对我的 JSON 输出进行分组

下面的解决方案POST

我正在序列化一个模型并得到这个输出:

[
    {
        "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": "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 的解决方案:

views.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)

serializers.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上将每个日期用于select对应的对象,然后我们序列化这些对象。

我们这样做得到了预期的结果,请注意,这将 2 DB hits 中产生 ,可能还有另一种方法可以在一次 DB 命中中完成,如果我想通了,我会更新我的答案

注意:我写这个是为了解释流程和逻辑我没有运行它,虽然它应该工作我可能会忘记一些会显示的东西给你一个错误,请随意尝试。

更新:如果您使用的是 SQLite,请检查此答案评论。