Django How To annotate/Group by & Display it in Serializer
Question:
I have following Model
class ModelAnswer(BaseModel):
questions = models.ForeignKey(
to=Question,
on_delete=models.CASCADE
)
answer = models.TextField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
Basically usecase is answer can be added multiple time i.e at once 3 answer can be added and all answers needed to be added for particular question
I just made another model to keep track of these things in next model for my easiness.
class AnswerLog(BaseModel):
answer = models.ForeignKey(to=ModelAnswer, on_delete=models.CASCADE, null=True, blank=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
order = models.PositiveIntegerField(null=True, blank=True)
I am getting my response in this format
[
{
"answer":{
"id":42,
"user":1,
"questions":"what did you do today",
"subcategory":"Circumstance",
"is_intentional":"False",
"answer":"I played well",
"created_at":"2022-09-05T21:00:57.604051"
},
"order":1,
"category":"sports"
},
{
"answer":{
"id":43,
"user":1,
"questions":"what was your achievment?",
"subcategory":"Result",
"is_intentional":"False",
"answer":"a broked my leg",
"created_at":"2022-09-05T21:00:57.626193"
},
"order":1,
"category":"sports"
}
]
I just want my above response in a bit easier format in this way just combine by order and category because both will be ( category can still be same for another answer so order will only be different for next answer i.e 2)
[{
"answer":[{
"id":42,
"user":1,
"questions":"what did you do today",
"subcategory":"Circumstance",
"is_intentional":"False",
"answer":"I played well",
"created_at":"2022-09-05T21:00:57.604051"
},{
"id":43,
"user":1,
"questions":"what was your achievment?",
"subcategory":"Result",
"is_intentional":"False",
"answer":"a broked my leg",
"created_at":"2022-09-05T21:00:57.626193"
}],
"order":1,
"category":"sports",
}
]
My serializer is as follows
class AnswerLogSerializer(serializers.ModelSerializer):
answer = ListAnswerSerializer()
category = serializers.CharField(source='answer.questions.category.name')
class Meta:
model = AnswerLog
fields = ['answer','order', 'category']
My view is as
class ListAnswerLogView(generics.ListAPIView):
serializer_class = serializers.AnswerLogSerializer
def get_queryset(self):
return AnswerLog.objects.all()
Answers:
View
from collections import defaultdict
class ListAnswerLogView(ListAPIView):
serializer_class = AnswerLogSerializer
def get_queryset(self):
grouped_answers = defaultdict(lambda: dict(answer=set()))
for answer_log in AnswerLog.objects.all():
grouped_by_key = (
answer_log.order,
answer_log.answer.questions.category
)
grouped_answers[grouped_by_key]['answer'].add(answer_log.answer)
for key in grouped_answers:
grouped_answers[key].update(dict(
order=key[0],
question_category=key[1]
))
return grouped_answers.values()
Serializer
class AnswerLogSerializer(serializers.ModelSerializer):
answer = ListAnswerSerializer(many=True)
category = serializers.CharField(source='question_category.name')
class Meta:
model = AnswerLog
fields = ['answer', 'order', 'category']
P.S. i tried a lot to solve the problem just using django queryset features, but each of them leads to a problem. So I went this way to use dictionary to solve the problem.
I have following Model
class ModelAnswer(BaseModel):
questions = models.ForeignKey(
to=Question,
on_delete=models.CASCADE
)
answer = models.TextField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
Basically usecase is answer can be added multiple time i.e at once 3 answer can be added and all answers needed to be added for particular question
I just made another model to keep track of these things in next model for my easiness.
class AnswerLog(BaseModel):
answer = models.ForeignKey(to=ModelAnswer, on_delete=models.CASCADE, null=True, blank=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
order = models.PositiveIntegerField(null=True, blank=True)
I am getting my response in this format
[
{
"answer":{
"id":42,
"user":1,
"questions":"what did you do today",
"subcategory":"Circumstance",
"is_intentional":"False",
"answer":"I played well",
"created_at":"2022-09-05T21:00:57.604051"
},
"order":1,
"category":"sports"
},
{
"answer":{
"id":43,
"user":1,
"questions":"what was your achievment?",
"subcategory":"Result",
"is_intentional":"False",
"answer":"a broked my leg",
"created_at":"2022-09-05T21:00:57.626193"
},
"order":1,
"category":"sports"
}
]
I just want my above response in a bit easier format in this way just combine by order and category because both will be ( category can still be same for another answer so order will only be different for next answer i.e 2)
[{
"answer":[{
"id":42,
"user":1,
"questions":"what did you do today",
"subcategory":"Circumstance",
"is_intentional":"False",
"answer":"I played well",
"created_at":"2022-09-05T21:00:57.604051"
},{
"id":43,
"user":1,
"questions":"what was your achievment?",
"subcategory":"Result",
"is_intentional":"False",
"answer":"a broked my leg",
"created_at":"2022-09-05T21:00:57.626193"
}],
"order":1,
"category":"sports",
}
]
My serializer is as follows
class AnswerLogSerializer(serializers.ModelSerializer):
answer = ListAnswerSerializer()
category = serializers.CharField(source='answer.questions.category.name')
class Meta:
model = AnswerLog
fields = ['answer','order', 'category']
My view is as
class ListAnswerLogView(generics.ListAPIView):
serializer_class = serializers.AnswerLogSerializer
def get_queryset(self):
return AnswerLog.objects.all()
View
from collections import defaultdict
class ListAnswerLogView(ListAPIView):
serializer_class = AnswerLogSerializer
def get_queryset(self):
grouped_answers = defaultdict(lambda: dict(answer=set()))
for answer_log in AnswerLog.objects.all():
grouped_by_key = (
answer_log.order,
answer_log.answer.questions.category
)
grouped_answers[grouped_by_key]['answer'].add(answer_log.answer)
for key in grouped_answers:
grouped_answers[key].update(dict(
order=key[0],
question_category=key[1]
))
return grouped_answers.values()
Serializer
class AnswerLogSerializer(serializers.ModelSerializer):
answer = ListAnswerSerializer(many=True)
category = serializers.CharField(source='question_category.name')
class Meta:
model = AnswerLog
fields = ['answer', 'order', 'category']
P.S. i tried a lot to solve the problem just using django queryset features, but each of them leads to a problem. So I went this way to use dictionary to solve the problem.