【问题标题】:Django filter on calculated field when calculated field returns the value based on combination of two model fields当计算字段基于两个模型字段的组合返回值时,Django过滤计算字段
【发布时间】:2018-07-03 12:54:33
【问题描述】:

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

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 个值 active、expired 或 complete。我不能直接在过滤字段中添加job_status字段,那么如何过滤呢?

更新1

根据回复,我的上述解决方案不正确。所以,如果我尝试通过创建两个不同的过滤器来解决这个问题,比如 is_complete 和 is_expired,但我仍然没有找到为 is_complete BooleanFilter 指定查询集的方法。我的 is_complete = True 应该给出条件 (is_complete is False and expiry_time >= now) 的结果,而 Is_complete = False 应该给出条件 (is_complete is False and expiry_time 如何编写此查询?

filters.py

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

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

【问题讨论】:

标签: django django-filter


【解决方案1】:

我建议使用类方法执行以下操作。不要误会我的意思,它没有直接实现过滤器功能,但这是可能的最 Pythonic 的工作。您现在要做的就是运行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)

【讨论】:

  • 不幸的是,过滤器集将不起作用,因为它仍在查询数据库。它的调用方式与我的函数基本相同。您可以使用将查询集传递给它而不是收集所有的相同概念来创建它。我会为此更新我的答案。
  • 我更新了答案以修复几个语法问题(从我的手机输入)。如果您仍有疑问,请告诉我。
猜你喜欢
  • 2016-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-06
  • 2018-06-15
  • 2018-07-19
  • 2021-02-17
相关资源
最近更新 更多