I have a model like this:
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
function returns true or false for each agreement
and I have a simple filter like this:
class AgreementFilter(filters.FilterSet):
file_no = filters.NumberFilter(lookup_expr='icontains')
class Meta:
model = Agreement
fields = ['file_no',]
I think that I cannot filter on the property field because Django filters operate at the database level. So how can I make it work to filter agreement model objects if it is valid or invalid or either true or false
I managed to write a custom filter for filtering the expired and valid agreements by using the 'method' parameter to specify a custom 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 will return if the object of the agreement is either true or false by calculation:
For expired agreements
http://127.0.0.1:8000/api/agreement/?is_expired=True
and For valid agreements
http://127.0.0.1:8000/api/agreement/?is_expired=False