【问题标题】:DRF - django_filters -Using custom methodsDRF - django_filters - 使用自定义方法
【发布时间】:2020-05-18 11:24:15
【问题描述】:

我有一个这样的模型:

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函数为每个协议返回真或假

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

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

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

我认为我无法过滤属性字段,因为 Django 过滤器在数据库级别运行。那么,如果协议模型对象有效或无效或真或假,我怎样才能使其工作呢

【问题讨论】:

  • “让过滤协议起作用”是什么意思?
  • 我想过滤有效或无效的协议模型对象

标签: django python-3.x django-rest-framework django-filters


【解决方案1】:

您可以在Agreement模型中添加新字段,以保持协议的到期日期:

expiry_date = models.DateField()

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

现在您希望在添加新记录时自动完成,为此您可以使用 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,这将非常简单,在前端只需使用当前日期并将其作为过滤器参数传递,以仅显示日期大于当前日期的协议。

【讨论】:

  • 感谢您的解决方案.. 但我已经通过编写自定义过滤器来完成它,这对我来说是一种更简单的方法。
【解决方案2】:

我设法编写了一个自定义过滤器,通过使用'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将返回:

对于过期的协议

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

适用于有效协议

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

【讨论】:

    猜你喜欢
    • 2019-06-01
    • 2020-10-15
    • 1970-01-01
    • 2021-04-18
    • 2016-03-29
    • 1970-01-01
    • 2018-08-24
    • 2022-12-14
    • 1970-01-01
    相关资源
    最近更新 更多