当计算字段基于两个模型字段的组合返回值时,对计算字段进行Django过滤

时间:2018-07-03 12:54:33

标签: django django-filter

如何过滤可基于同一模型中两个模型字段的组合来确定其值的计算字段?

Models.py

class Job(models.Model):
    start_time = models.DateTimeField(auto_now_add=True)
    end_time = models.DateTimeField(null=True)
    expiry_time = models.DateTimeField(null=True)
    is_complete = models.BooleanField(default=True)

    def _get_job_status(self):
        if self.is_complete is False and self.expiry_time >= now:
            return "active"
        elif self.is_complete is False and self.expiry_time < now:
            return "expired"
        else:
            return "complete"

    job_status = property(_get_job_status)

我要过滤job_status字段,该字段可以有3个有效,过期或完整的值。我无法直接在过滤器字段中添加job_status字段,那么如何对其进行过滤?

更新1

根据回答,我的上述解决方案不正确。因此,如果我尝试通过创建两个不同的过滤器(例如 is_complete is_expired )来解决此问题,但仍然找不到为is_complete BooleanFilter指定查询集的方法。我的is_complete = True应该为条件给出结果(is_complete为False并且expiry_time> = now),而Is_complete = False应该给条件提供结果 complete(is_complete为False并且expiry_time 如何编写此查询?

filters.py

class JobStatusFilter(FilterSet):
    is_active = filters.BooleanFilter(name="is_complete")

    class Meta:
        model = Job
        fields = ('is_complete',)

1 个答案:

答案 0 :(得分:0)

我建议对类方法进行以下操作。不要误会我的意思,它不是直接实现filter函数,但这是可能的最Python化的工作。您现在所要做的就是运行Job.filter_job_status('active', queryset or None),以获取所有处于活动状态的作业。这样做的主要好处是为了在整个地方重复相同的查询步骤。这将返回一个查询集,您需要做的就是过滤掉更多数据。

# models.py
class Job(models.Model):
    start_time = models.DateTimeField(auto_now_add=True)
    end_time = models.DateTimeField(null=True)
    expiry_time = models.DateTimeField(null=True)
    is_complete = models.BooleanField(default=True)

    def _get_job_status(self):
        if self.is_complete is False and self.expiry_time >= now:
            return "active"
        elif self.is_complete is False and self.expiry_time < now:
            return "expired"
        else:
            return "complete"

    # Not sure if it matters but the property might need to be above the 
    # class method.
    job_status = property(_get_job_status)

    # Might be a bit database heavy but it will work for 99.9999% of 
    # situations.
    @classmethod
    def filter_job_status(cls, status, queryset=None):
        job_matches = []
        if queryset is None:
            queryset = cls.objects.all()
        assert queryset.model is cls, \
            "filter job status only accepts Job querysets."
        for job in queryset:
            if status in job.job_status:
                job_matches.append(job.pk)
        # return queryset to allow more filtering if needed
        return cls.objects.filter(pk__in=job_matches)