我们如何计算日期时间字段与 django 中相关 table 的平均差异?

How can we calculate average difference of datetime fields from related table in django?

我有两个模型 GigsOrders。 并想计算每个演出的 order_start_timeorder_completed_time 之间的平均差异。检查我的代码是否给出以下错误

无法将关键字 'orders' 解析为字段。选项包括:类别、category_id、详细信息、演出、ID、图片、价格、评论、卖家、seller_id、标题

请帮忙!

Models.py(在卖家应用中)

class Gigs(models.Model):
    title = models.CharField(max_length=255)
    category = models.ForeignKey(Categories , on_delete=models.CASCADE)
    images = models.ImageField(blank=True, null = True, upload_to= upload_path)
    price = models.DecimalField(max_digits=6, decimal_places=2)
    details = models.TextField()
    seller = models.ForeignKey(User,default=None, on_delete=models.CASCADE)
 
    @property
    def average_completionTime(self):
        if self._average_completionTime is not None:
            return self._average_completionTime
        return self.gig.aggregate(Avg('order_completed_time'-'order_start_time'))

我认为这里的问题是平均完成时间如何在我应该在 views.py

中引用的一个变量中使用 'order_completed_time'-'order_start_time'

Models.py(在买家应用中)

关注项目字段

from seller.models import Gigs
class Orders(models.Model):
    buyer = models.ForeignKey(User,default=None, on_delete=models.CASCADE,related_name='buyer_id')
    seller = models.ForeignKey(User,default=None, on_delete=models.CASCADE,related_name='seller_id')
    item = models.ForeignKey(Gigs,default=None, on_delete=models.CASCADE,related_name='gig')
    payment_method= models.CharField(max_length=10)
    address = models.CharField(max_length=255)
    mobile = models.CharField(max_length=13,default=None)
    quantity = models.SmallIntegerField(default=1)
    status = models.CharField(max_length=13,default='new order')
    order_start_time = models.DateTimeField(default=None)
    order_completed_time = models.DateTimeField(default=None)
    created_at = models.DateTimeField(auto_now_add=True)

Views.py

class RetrieveGigsAPI(GenericAPIView, RetrieveModelMixin):
    def get_queryset(self):
        return Gigs.objects.all().annotate(_average_rating=Avg('orders__time'))
    serializer_class = GigsSerializerWithAvgTime
    permission_classes = (AllowAny,)

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

Serializers.py

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

F() 对象表示模型字段的值,它引用模型字段值并使用它们执行数据库操作。更多详情,https://docs.djangoproject.com/en/3.2/ref/models/expressions/#f-expressions

from django.db.models import F

let say queryset = Gigs.objects.all()

#you add '_average_completionTime' in the queryset
queryset = queryset.annotate(_average_completionTime=Avg(F('gig__order_completed_time') - F('gig__order_start_time'))

您可以像这样用平均完成时间来注释每个演出:

    def get_queryset(self):
        return Gigs.objects.annotate(
            _average_completionTime=Avg(
                F('gig__order_completed_time') - F('gig__order_start_time')
            )
        )

在您的 average_completionTime 模型方法中,如果未设置 self._average_completionTime,您还需要使用 F 表达式:

    @property
    def average_completionTime(self):
        if getattr(self, '_average_completionTime', None):
            return self._average_completionTime
        return self.gig.aggregate(Avg(F('order_completed_time') - F('order_start_time')))

更新:

我无法重现 'decimal.Decimal' object has no attribute 'tzinfo' 错误。

不知道为什么,但是基于 this answer, you can try to use ExpressionWrapper 来避免同样的错误,所以:

from django.db.models import DurationField, ExpressionWrapper, F


class GigsSerializerWithAvgTime(serializers.ModelSerializer):
    def get_queryset(self):
        return Gigs.objects.annotate(
            _average_completionTime=Avg(
                ExpressionWrapper(F('gig__order_completed_time') - F('gig__order_start_time'), output_field=DurationField())
            )
        )

或者正如@Abdul Aziz Barkat 所提到的,将 output_field 添加到 Avg 聚合中,如下所示:

        return Gigs.objects.annotate(
            _average_completionTime=Avg(
                F('gig__order_completed_time') - F('gig__order_start_time'), output_field=DurationField()
            )
        )