Skip to content

Commit

Permalink
improve filtering by amount
Browse files Browse the repository at this point in the history
  • Loading branch information
madjid-asa committed Feb 20, 2024
1 parent 8dd8f1a commit c6fa666
Showing 1 changed file with 40 additions and 7 deletions.
47 changes: 40 additions & 7 deletions lemarche/tenders/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from django.conf import settings
from django.contrib.contenttypes.fields import GenericRelation
from django.db import IntegrityError, models, transaction
from django.db.models import BooleanField, Case, Count, ExpressionWrapper, F, IntegerField, Q, Sum, When
from django.db.models import BooleanField, Case, Count, ExpressionWrapper, F, IntegerField, Q, Sum, Value, When
from django.db.models.functions import Greatest
from django.urls import reverse
from django.utils import timezone
Expand Down Expand Up @@ -107,19 +107,52 @@ def is_live(self):
return self.sent().filter(deadline_date__gte=datetime.today())

def has_amount(self):
return self.filter(Q(amount__isnull=False) | Q(amount_exact__isnull=False))
return self.filter(Q(amount__isnull=False) | Q(amount_exact__isnull=False)).annotate(
has_amount_exact=Case(
When(amount_exact__isnull=False, then=Value(True)), default=Value(False), output_field=BooleanField()
)
)

def filter_by_amount(self, amount: int, operation: str = "gte"):
"""
Filters records based on a monetary amount with a specified comparison operation.
It dynamically selects between filtering on an exact amount (`amount_exact`)
or predefined amount ranges when the exact amount is not available for a record.
Supported operations are 'gte' (>=), 'gt' (>), 'lte' (<=), and 'lt' (<).
Requires an annotated `has_amount_exact` in the queryset indicating the presence of `amount_exact`.
Args:
amount (int): Amount to filter by, in the smallest currency unit (e.g., cents).
operation (str, optional): Comparison operation ('gte', 'gt', 'lte', 'lt'). Defaults to 'gte'.
def filter_by_amount(self, amount, operation: str = "gte"):
Returns:
QuerySet: Filtered queryset based on the amount and operation.
Example:
>>> filtered_queryset = MyModel.objects.all().filter_by_amount(5000, 'gte')
Filters for records with `amount_exact` >= 5000 or in the matching amount range.
"""
amounts_keys = find_amount_ranges(amount=amount, operation=operation)
queryset = self.has_amount()
if operation == "gte":
return queryset.filter(Q(amount__in=amounts_keys) | Q(amount_exact__gte=amount))
queryset = queryset.filter(
Q(has_amount_exact=True, amount_exact__gte=amount) | Q(has_amount_exact=False, amount__in=amounts_keys)
)
elif operation == "gt":
return queryset.filter(Q(amount__in=amounts_keys) | Q(amount_exact__gt=amount))
queryset = queryset.filter(
Q(has_amount_exact=True, amount_exact__gt=amount) | Q(has_amount_exact=False, amount__in=amounts_keys)
)
elif operation == "lte":
return queryset.filter(Q(amount__in=amounts_keys) | Q(amount_exact__lte=amount))
queryset = queryset.filter(
Q(has_amount_exact=True, amount_exact__lte=amount) | Q(has_amount_exact=False, amount__in=amounts_keys)
)
elif operation == "lt":
return queryset.filter(Q(amount__in=amounts_keys) | Q(amount_exact__lt=amount))
queryset = queryset.filter(
Q(has_amount_exact=True, amount_exact__lt=amount) | Q(has_amount_exact=False, amount__in=amounts_keys)
)
return queryset

def in_perimeters(self, post_code, department, region):
filters = (
Expand Down

0 comments on commit c6fa666

Please sign in to comment.