I have a post model that can have ratings:
Here is the post model:
class Post(models.Model):
category = models.ForeignKey(Category, on_delete=models.SET_DEFAULT, default=1, related_name="posts")
body = models.TextField("content", blank=True, null=True, max_length=5000)
slug = AutoSlugField(populate_from=["category", "created_at"])
video = models.FileField(upload_to=video_directory_path, null=True, blank=True)
user = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="posts"
)
published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "post"
verbose_name_plural = "posts"
db_table = "posts"
ordering = ["created_at"]
get_latest_by = "created_at"
def __str__(self):
return self.body[0:30]
def get_absolute_url(self):
return self.slug
def one_image(self):
return PostImage.objects.all().filter(post=self)[:1]
and here is the post rating model:
class PostRating(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="ratings")
score = models.IntegerField(choices=list(zip(range(1, 6), range(1, 6))))
user = models.ForeignKey(
User, on_delete=models.CASCADE, verbose_name="user rating"
)
created_at = models.DateTimeField(auto_now_add=True, verbose_name="created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="updated at")
class Meta:
verbose_name = "post rating"
verbose_name_plural = "post ratings"
db_table = "post_ratings"
def __str__(self):
return str(self.score)
Here is the serializer:
class PostSerializer(serializers.ModelSerializer):
images = PostImageSerializer(many=True, read_only=True, required=False)
class Meta:
model = Post
fields = [
"id",
"category",
"body",
"images",
"video",
"ratings",
"published",
"created_at",
"updated_at",
]
depth = 1
def create(self, validated_data):
user = User.objects.get(id=self.context['request'].data.get('user'))
category = Category.objects.get(id=self.context['request'].data.get('category'))
new_post = Post.objects.create(**validated_data, category=category, user=user)
images = dict((self.context['request'].FILES).lists()).get('images', None)
if images:
for image in images:
PostImage.objects.create(
image=image, post=new_post
)
return new_post
QUESTION:
In the serializer I have the related field 'ratings' and it displays an array with each of the ratings, which is great but I only want to get the total amount of ratings and the average. How can I get that in the serializer so I can display it on the front end as a ratings total and a ratings average.
CodePudding user response:
If I understand your question You can do this way.
class PostSerializer(serializers.ModelSerializer):
images = PostImageSerializer(many=True, read_only=True, required=False)
total_ratings = serializers.SerializerMethodField()
average_rating = serializers.SerializerMethodField()
class Meta:
model = Post
fields = [
"id",
"category",
"body",
"images",
"video",
"ratings",
"total_ratings",
"average_rating",
"published",
"created_at",
"updated_at",
]
depth = 1
def get_total_ratings(self, obj):
return obj.ratings.count()
def get_average_rating(self, obj):
total = obj.ratings.aggregate(Sum('score'))['score__sum']
if total:
return total / obj.ratings.count()
return 0
#rest of your logic and code