Reputation: 3
Problem: Not able to group my JSON output by date
SOLUTION IN BOTTOM OF THIS POST
I am serializing a model and getting this output:
[
{
"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
}
},
I want to get it like the JSON below and group it by 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
},
}
]
I have one model:
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()
Trying to serialize and group the JSON by date:
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,
}
The code lets me custom the field layout, but not really grouping it by date. Do you have any suggestions on how to structure it?
Many thanks for all help!
in case its needed, here is my 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)
SOLUTION BY 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
Upvotes: 0
Views: 1832
Reputation: 1330
You can do something like this
Let's start first with your view, I will tweak the queryset like that
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)
Then on your 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
And finally, create WorkoutSerializer
class WorkoutSerializer(serializers.Serializers):
name = serializers.CharField()
exercise = serializers.IntegerField()
repetitions = serializers.IntegerField()
weight = serializers.IntegerField()
The previous way will first be got to the DB to get the distinct
dates then on WorkoutLogSerializer
will use each date to select the corresponding objects that have it, then we serialize those objects.
We get the intended result by doing so, note that this will result in 2 DB hits
, there may be another way that will do it in one DB hit, I will update my answer if I have figured it out
NOTE: I have written this to explain the flow and the logic I didn't run it, although it should work I may forget something that will show an error for you, feel free to try it.
UPDATE: check this answer comments if you are using SQLite.
Upvotes: 2