DRF - django_filters - 使用自定义方法

DRF - django_filters -Using custom methods

我有这样一个模型:

class Agreement(models.Model):
    file_no = models.IntegerField(primary_key=True)
    contract_date = models.DateField()
    contract_time = models.IntegerField()

    @property
    def calculate_expiry_date(self):
        return self.contract_date + relativedelta(years=self.contract_time)

    @property
    def is_expired(self):
        return (self.contract_date + relativedelta(years=self.contract_time)) < timezone.now().date() 

is_expired函数returns每个协议的真假

我有一个像这样的简单过滤器:

class AgreementFilter(filters.FilterSet):
    file_no = filters.NumberFilter(lookup_expr='icontains')

    class Meta:
        model = Agreement
        fields = ['file_no',] 

我认为我无法在 属性 字段上进行过滤,因为 Django 过滤器在数据库级别运行。那么,如果协议模型对象有效或无效,或者是真还是假,我该如何过滤协议模型对象

您可以向 Agreement 模型添加新字段以保留协议的到期日期:

expiry_date = models.DateField()

如果contract_time字段是合同有效的年数并且您在添加新合同时知道它,那么您可以像现在一样计算到期日并添加它到 expiry_date 字段而不需要 属性 装饰器。

现在您希望它在添加新记录时自动完成,为此您可以使用 pre_save signals.

from django.dispatch import receiver
from django.db.models import signals

@receiver(signals.pre_save, sender=WorkDone)
def calculate_expiry_date(sender, instance, **kwargs):
    instance.expiry_date = instances.contract_date + \
       relativedelta(years=instance.contract_time)

对于过滤部分,您可以使用当前日期来过滤记录。由于您使用的是 DRF,这将非常简单,在前端只需使用当前日期并将其作为过滤器参数传递以显示仅显示日期大于当前日期的协议。

我设法编写了一个自定义过滤器,用于通过使用 'method' 参数指定自定义方法来过滤过期和有效的协议 - see django-filter docs

from datetime import timedelta
from django.db.models import F, Case, When, BooleanField
from django_filters import rest_framework as filters

class AgreementFilter(filters.FilterSet):

    file_no = filters.NumberFilter(lookup_expr='icontains')
    is_expired = filters.BooleanFilter(method='filter_is_expired')

    class Meta:
        model = Agreement
        fields = ['file_no',] 

      def filter_is_expired(self, queryset, name, value):
        if value is not None:
            queryset = queryset.annotate(

                expired=Case(When(contract_date__lt=timezone.now().date() - (timedelta(days=365) * F('contract_time')),
                             then=True), default=False, output_field=BooleanField())).filter(expired=value)
        return queryset

Queryset 将return 如果协议对象通过计算为真或假:

对于过期的协议

http://127.0.0.1:8000/api/agreement/?is_expired=True

对于有效协议

http://127.0.0.1:8000/api/agreement/?is_expired=False