Django QuertySet.annotate()接收到非表达式-如何基于模型字段添加派生字段?
第一次和Django在一起。正在尝试向queryset添加批注:Django QuertySet.annotate()接收到非表达式-如何基于模型字段添加派生字段?,django,django-rest-framework,django-queryset,Django,Django Rest Framework,Django Queryset,第一次和Django在一起。正在尝试向queryset添加批注: class EnrollmentManager(models.Manager.from_queryset(EnrollmentCustomQuerySet)): COURSE_DURATION = datetime.timedelta(days=183) def get_queryset(self): """Overrides the models.Manager method""" lookba
class EnrollmentManager(models.Manager.from_queryset(EnrollmentCustomQuerySet)):
COURSE_DURATION = datetime.timedelta(days=183)
def get_queryset(self):
"""Overrides the models.Manager method"""
lookback = make_aware(datetime.datetime.today() - self.COURSE_DURATION)
qs = super(EnrollmentManager, self).get_queryset().annotate( \
is_expired=(Value(True)), output_field=models.BooleanField())
return qs
目前,我正试图在返回的queryset上添加一个额外的“computed”字段,该字段硬编码为True,属性/字段应被称为已过期
如果我可以让它工作,那么Value(True)需要是基于以下表达式的派生值:
F('enrolled') < lookback
在贝壳里我可以看到:
Enrollment.objects.all()[0].is_expired -> returns True
我可以将其添加到序列化程序:
class EnrollmentSerializer(serializers.ModelSerializer):
is_active = serializers.SerializerMethodField()
is_current = serializers.SerializerMethodField()
is_expired = serializers.SerializerMethodField()
COURSE_DURATION = datetime.timedelta(days=183)
class Meta:
model = Enrollment
fields = ('id', 'is_active', 'is_current', 'is_expired')
def get_is_expired(self, obj):
return obj.is_expired
所以这是可能的……但我如何用计算替换硬编码的“真”呢
更新
在阅读报告时,它指出:
“使用提供的查询表达式列表注释QuerySet中的每个对象。表达式可以是简单值、对模型(或任何相关模型)上字段的引用,也可以是在与查询集中的对象相关的对象上计算的聚合表达式(平均值、总和等)。”
一个简单的值-那么,不是一个简单的计算值吗
这让我觉得这是不可能的…这似乎是一个非常好的
案例
表达式的用例。我建议您尽可能熟悉它,它们非常有用
我还没有测试过这个,但它应该可以工作。我假设他们第一次注册的时候,注册是一个tz感知的日期时间
from django.db.models import Case, When, Value
def get_queryset(self):
"""Overrides the models.Manager method"""
lookback = make_aware(datetime.datetime.today() - self.COURSE_DURATION)
qs = super(EnrollmentManager, self).get_queryset().annotate(
is_expired=Case(
When(
enrolled__lt=lookback,
then=Value(True)
),
default=Value(False),
output_field=models.BooleanField()
)
)
您也不必预先计算lookback变量。请查看ExpressionWrappers,它解决了这个问题
ExpressionWrapper(
TruncDate(F('date1')) + datetime.timedelta(days=365),
output_field=DateField(),
)
ExpressionWrapper(
TruncDate(F('date1')) + datetime.timedelta(days=365),
output_field=DateField(),
)