Files
django-nepkit/django_nepkit/filters.py
T
sankalp c6301686cc feat: add Nepali currency support, number-to-words conversion, and REST API enhancements
- Implement NepaliCurrencyField for model-level currency handling.
- Add format_nepali_currency utility with Lakhs/Crores comma formatting and decimal support.
- Implement number_to_nepali_words and english_to_nepali_unicode helper functions.
- Add nepali_currency, nepali_words, and nepali_unicode template filters.
- Enhance REST API (DRF) support:
    - Added NepaliCurrencySerializerField for formatted currency output.
    - Added NepaliLocalizedSerializerMixin for automatic Devanagari field generation.
    - Added flexible NepaliCurrencyRangeFilter and NepaliDateRangeFilter.
- Integrated automatic currency formatting into NepaliModelAdmin.
- Expanded the example demo app with a Transaction model and updated filters.
- Added comprehensive unit tests for formatting, models, and API components.
- Updated documentation (README.md and todo.md) to reflect new features.
2026-01-30 20:06:39 +05:45

114 lines
3.8 KiB
Python

from __future__ import annotations
from typing import Any
from django.db.models import QuerySet
try:
from django_filters import rest_framework as filters
except ImportError as e:
raise ModuleNotFoundError(
"django-nepkit filter support is optional. Install with `django-nepkit[drf]` "
"to use `django_nepkit.filters`."
) from e
class NepaliDateYearFilter(filters.NumberFilter):
"""
A filter for `NepaliDateField` that allows filtering by Bikram Sambat Year.
Expects an integer year (e.g., 2080).
"""
def filter(self, qs: QuerySet, value: Any) -> QuerySet:
if value:
from django_nepkit.utils import BS_DATE_FORMAT
# Find the date separator (e.g., '-' in '2080-01-01')
if BS_DATE_FORMAT.startswith("%Y"):
separator = BS_DATE_FORMAT[2] if len(BS_DATE_FORMAT) > 2 else "-"
return qs.filter(
**{f"{self.field_name}__startswith": f"{value}{separator}"}
)
# Fallback if the format is unusual
return qs.filter(**{f"{self.field_name}__icontains": str(value)})
return qs
class NepaliDateMonthFilter(filters.NumberFilter):
"""
A filter for `NepaliDateField` that allows filtering by Bikram Sambat Month.
Expects an integer month (1-12).
"""
def filter(self, qs: QuerySet, value: Any) -> QuerySet:
if value:
from django_nepkit.utils import BS_DATE_FORMAT
month_str = f"{int(value):02d}"
# Standard format: look for '-01-' for Baisakh
if BS_DATE_FORMAT == "%Y-%m-%d":
return qs.filter(**{f"{self.field_name}__contains": f"-{month_str}-"})
# Adaptive check for other separators
separator = BS_DATE_FORMAT[2] if len(BS_DATE_FORMAT) > 2 else "-"
return qs.filter(
**{f"{self.field_name}__contains": f"{separator}{month_str}{separator}"}
)
return qs
class NepaliDateRangeFilter(filters.CharFilter):
"""
A filter for `NepaliDateField` that allows filtering by a range of BS dates.
Supports:
- "start,end" -> range
- "start," -> greater than or equal
- ",end" -> less than or equal
- "date" -> exact match
"""
def filter(self, qs: QuerySet, value: Any) -> QuerySet:
if value:
parts = [p.strip() for p in str(value).split(",")]
if len(parts) == 1:
return qs.filter(**{self.field_name: parts[0]})
if len(parts) == 2:
if parts[0] and parts[1]:
return qs.filter(
**{f"{self.field_name}__range": (parts[0], parts[1])}
)
if parts[0]:
return qs.filter(**{f"{self.field_name}__gte": parts[0]})
if parts[1]:
return qs.filter(**{f"{self.field_name}__lte": parts[1]})
return qs
class NepaliCurrencyRangeFilter(filters.CharFilter):
"""
A filter for `NepaliCurrencyField` that allows range filtering.
Supports:
- "min,max" -> range
- "min," -> greater than or equal
- ",max" -> less than or equal
- "value" -> exact match
"""
def filter(self, qs: QuerySet, value: Any) -> QuerySet:
if value:
parts = [p.strip() for p in str(value).split(",")]
if len(parts) == 1:
return qs.filter(**{self.field_name: parts[0]})
if len(parts) == 2:
if parts[0] and parts[1]:
return qs.filter(
**{f"{self.field_name}__range": (parts[0], parts[1])}
)
if parts[0]:
return qs.filter(**{f"{self.field_name}__gte": parts[0]})
if parts[1]:
return qs.filter(**{f"{self.field_name}__lte": parts[1]})
return qs