django - 如何计算 Django 模型中某些字段的平均值并将其发送到 rest API?

标签 django django-models django-rest-framework django-views

我想计算评分的平均值(在评论模型中)并将其发送到我的 API。

模型.py

from django.db import models
from adminuser.models import Categories
from accounts.models import UserAccount as User
from django.core.validators import MaxValueValidator, MinValueValidator

# Create your models here.
class Gigs(models.Model):
    title = models.CharField(max_length=255)
    category = models.ForeignKey(Categories , on_delete=models.CASCADE)
    price = models.DecimalField(max_digits=6, decimal_places=2)
    details = models.TextField()
    seller = models.ForeignKey(User,default=None, on_delete=models.CASCADE)

class Reviews(models.Model):
    rating = models.SmallIntegerField( default=0,validators=[MaxValueValidator(5),MinValueValidator(1)])
    comment = models.CharField(max_length=500)
    item =  models.ForeignKey(Gigs , on_delete=models.CASCADE)
    buyer = models.ForeignKey(User ,default=None, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)

Views.py

from django.shortcuts import render
from .models import Gigs,Reviews
from .serializers import GigsSerializer,ReviewsSerializer
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin , RetrieveModelMixin , DestroyModelMixin, UpdateModelMixin
from rest_framework.permissions import AllowAny
# Create your views here.

#List and create (pk not required)
class GigsListAPI(GenericAPIView, ListModelMixin ):
    def get_queryset(self):
       username = self.kwargs['user']
       return Gigs.objects.filter(seller=username)
    serializer_class = GigsSerializer
    permission_classes = (AllowAny,)

    def get(self, request , *args, **kwargs):
        return self.list(request, *args, **kwargs)
class GigsListCategorywise(GenericAPIView, ListModelMixin ):
    def get_queryset(self):
       SearchedCategory = self.kwargs['category']
       return Gigs.objects.filter(category=SearchedCategory)
    serializer_class = GigsSerializer
    permission_classes = (AllowAny,)

    def get(self, request , *args, **kwargs):
        return self.list(request, *args, **kwargs)

class GigsListAll(GenericAPIView, ListModelMixin ):
    queryset = Gigs.objects.all()
    serializer_class = GigsSerializer
    permission_classes = (AllowAny,)

    def get(self, request , *args, **kwargs):
        return self.list(request, *args, **kwargs)

class GigsCreateAPI(GenericAPIView, CreateModelMixin):
    queryset = Gigs.objects.all()
    serializer_class = GigsSerializer
    permission_classes = (AllowAny,)

    def post(self, request , *args, **kwargs):
        return self.create(request, *args, **kwargs)

# Retrieve, update and delete (pk required)
class RUDGigsAPI(GenericAPIView, RetrieveModelMixin, UpdateModelMixin,  DestroyModelMixin):
    queryset = Gigs.objects.all()
    serializer_class = GigsSerializer
    permission_classes = (AllowAny,)

    def get(self, request , *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)
    
    def put(self, request , *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def put(self, request , *args, **kwargs):
        return self.partial_update(request, *args, **kwargs)
    
    def delete(self, request , *args, **kwargs): 
        pk = kwargs.get('pk')
        p = Gigs.objects.get(id=pk)
        if p.images:
            p.images.delete() 
        return self.destroy(request, *args, **kwargs)



# VIEWS FOR REVIEWS MODEL
class ReviewsListAPI(GenericAPIView, ListModelMixin ):
    def get_queryset(self):
       item = self.kwargs['item']
       return Reviews.objects.filter(item=item)
    serializer_class = ReviewsSerializer
    permission_classes = (AllowAny,)

    def get(self, request , *args, **kwargs):
        return self.list(request, *args, **kwargs)

class ReviewsCreateAPI(GenericAPIView, CreateModelMixin):
    queryset = Reviews.objects.all()
    serializer_class = ReviewsSerializer
    permission_classes = (AllowAny,)

    def post(self, request , *args, **kwargs):
        return self.create(request, *args, **kwargs)

序列化器.py

from rest_framework import serializers
from .models import Gigs, Reviews

class GigsSerializer (serializers.ModelSerializer):
    class Meta:
        model = Gigs
        fields = ['id','title','category','price','details','seller','images']

class ReviewsSerializer (serializers.ModelSerializer):
    class Meta:
        model = Reviews
        fields = ['id','rating','comment','item','buyer','created_at']

我想计算评论表中某些演出或项目的平均评分,然后将其发送到 API。但我很困惑在哪里计算它(models.py 或 views.py)以及如何将它发送到我的 API。

最佳答案

好吧,我要详细解释一下,平均评分可以被认为是 Gigs 中的一个虚拟字段,所以把它放在那里是有意义的,所以让我们试试看:

class Gigs(models.Model):
    ...

    @property
    def average_rating(self):
        return self.reviews.aggregate(Avg('rating'))['rating_avg']

所以当您要检索单个 Gig 时,这很好,但问题是如果您需要列表 api 中的平均值,这将产生很多额外的查询(每个 Gig 1 个)。在这种情况下,最好在 View 中批量执行,因此:

class GigsListAll(ListModelMixin, GenericAPIView): # you should put the mixin before the main class :D
    serializer_class = GigsSerializer
    permission_classes = (AllowAny,)

    def get_queryset(self):

        return Gigs.objects.all().annotate(_average_rating=Avg('reviews__rating') # pay attention, it was annotated as _average_rating

现在我们要更改模型中的虚拟场,并检查我们是否预先计算了它,所以:

class Gigs(models.Model):
...

    @property
    def average_rating(self):
        if hasattr(self, '_average_rating'):
            return self._average_rating
        return self.reviews.aggregate(Avg('rating'))

最后在你的序列化器中使用它:

class GigsSerializer (serializers.ModelSerializer):
average_rating = serializers.SerializerMethodField()
def get_average_rating(self, obj):
    return obj.average_rating
class Meta:
    model = Gigs
    fields = ['id','title','category','price','details','seller','images','average_rating']

附注为外键设置相关名称是最佳实践,因此请像这样更改您的 reviews 模型:

class Reviews(models.Model):
    ...
    item = models.ForeignKey(Gigs , on_delete=models.CASCADE, related_name='reviews')

关于django - 如何计算 Django 模型中某些字段的平均值并将其发送到 rest API?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68953258/

相关文章:

django - 只从查询集中获取某个类型的最新项目

python - django heroku makemigrations 忽略模型中的更改

Django 使用带有 djoser 的电子邮件身份验证进行登录

python - Django 序列化器字段值基于同一序列化器中的其他字段

python - Django 序列化器类相互引用

javascript - 为什么 Ajax 在通过 POST 方法提交表单后会在移动设备上刷新页面?

django - 如何在 Django 中检索远程端口

django - 为什么不再推荐gunicorn_django?

python - Aldryn - DjangoCMS 安装插件不存在于 "Manage Addons"

Django 模型 : how to find list of auto-generated fields