django-nepkit 0.1.0__py3-none-any.whl → 0.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_nepkit/__init__.py +20 -0
- django_nepkit/admin.py +243 -93
- django_nepkit/conf.py +34 -0
- django_nepkit/constants.py +129 -0
- django_nepkit/filters.py +113 -0
- django_nepkit/forms.py +9 -9
- django_nepkit/lang_utils.py +52 -0
- django_nepkit/models.py +138 -161
- django_nepkit/serializers.py +127 -28
- django_nepkit/static/django_nepkit/js/address-chaining.js +129 -29
- django_nepkit/static/django_nepkit/js/nepal-data.js +1 -0
- django_nepkit/static/django_nepkit/js/nepali-datepicker-init.js +55 -46
- django_nepkit/utils.py +270 -46
- django_nepkit/validators.py +1 -1
- django_nepkit/views.py +127 -10
- django_nepkit/widgets.py +100 -31
- django_nepkit-0.2.1.dist-info/METADATA +308 -0
- django_nepkit-0.2.1.dist-info/RECORD +37 -0
- example/demo/admin.py +45 -21
- example/demo/models.py +41 -4
- example/demo/serializers.py +39 -0
- example/demo/urls.py +13 -2
- example/demo/views.py +125 -3
- example/example_project/settings.py +10 -0
- example/example_project/urls.py +1 -1
- example/manage.py +2 -2
- django_nepkit/templatetags/__init__.py +0 -0
- django_nepkit/templatetags/nepali.py +0 -74
- django_nepkit-0.1.0.dist-info/METADATA +0 -377
- django_nepkit-0.1.0.dist-info/RECORD +0 -39
- example/demo/migrations/0001_initial.py +0 -2113
- example/demo/migrations/0002_alter_person_phone_number.py +0 -18
- example/demo/migrations/0003_person_created_at_person_updated_at.py +0 -27
- example/demo/migrations/0004_alter_person_created_at_alter_person_updated_at.py +0 -23
- example/demo/migrations/0005_alter_person_created_at_alter_person_updated_at.py +0 -27
- example/demo/migrations/__init__.py +0 -0
- {django_nepkit-0.1.0.dist-info → django_nepkit-0.2.1.dist-info}/WHEEL +0 -0
- {django_nepkit-0.1.0.dist-info → django_nepkit-0.2.1.dist-info}/licenses/LICENSE +0 -0
- {django_nepkit-0.1.0.dist-info → django_nepkit-0.2.1.dist-info}/top_level.txt +0 -0
django_nepkit/__init__.py
CHANGED
|
@@ -6,14 +6,26 @@ from .models import (
|
|
|
6
6
|
ProvinceField,
|
|
7
7
|
DistrictField,
|
|
8
8
|
MunicipalityField,
|
|
9
|
+
NepaliCurrencyField,
|
|
9
10
|
)
|
|
10
11
|
from .admin import (
|
|
11
12
|
NepaliDateFilter,
|
|
13
|
+
NepaliMonthFilter,
|
|
12
14
|
format_nepali_date,
|
|
13
15
|
format_nepali_datetime,
|
|
14
16
|
NepaliModelAdmin,
|
|
15
17
|
NepaliAdminMixin,
|
|
16
18
|
)
|
|
19
|
+
from .serializers import (
|
|
20
|
+
NepaliCurrencySerializerField,
|
|
21
|
+
NepaliLocalizedSerializerMixin,
|
|
22
|
+
)
|
|
23
|
+
from .filters import (
|
|
24
|
+
NepaliDateYearFilter,
|
|
25
|
+
NepaliDateMonthFilter,
|
|
26
|
+
NepaliDateRangeFilter,
|
|
27
|
+
NepaliCurrencyRangeFilter,
|
|
28
|
+
)
|
|
17
29
|
|
|
18
30
|
__all__ = [
|
|
19
31
|
"NepaliDateField",
|
|
@@ -24,8 +36,16 @@ __all__ = [
|
|
|
24
36
|
"DistrictField",
|
|
25
37
|
"MunicipalityField",
|
|
26
38
|
"NepaliDateFilter",
|
|
39
|
+
"NepaliMonthFilter",
|
|
27
40
|
"format_nepali_date",
|
|
28
41
|
"format_nepali_datetime",
|
|
29
42
|
"NepaliModelAdmin",
|
|
30
43
|
"NepaliAdminMixin",
|
|
44
|
+
"NepaliCurrencyField",
|
|
45
|
+
"NepaliCurrencySerializerField",
|
|
46
|
+
"NepaliLocalizedSerializerMixin",
|
|
47
|
+
"NepaliDateYearFilter",
|
|
48
|
+
"NepaliDateMonthFilter",
|
|
49
|
+
"NepaliDateRangeFilter",
|
|
50
|
+
"NepaliCurrencyRangeFilter",
|
|
31
51
|
]
|
django_nepkit/admin.py
CHANGED
|
@@ -2,77 +2,71 @@ from django.contrib import admin
|
|
|
2
2
|
from django.utils.translation import gettext_lazy as _
|
|
3
3
|
from nepali.datetime import nepalidate, nepalidatetime
|
|
4
4
|
|
|
5
|
-
from django_nepkit.
|
|
5
|
+
from django_nepkit.conf import nepkit_settings
|
|
6
|
+
from django_nepkit.models import (
|
|
7
|
+
NepaliDateField,
|
|
8
|
+
NepaliDateTimeField,
|
|
9
|
+
NepaliCurrencyField,
|
|
10
|
+
)
|
|
6
11
|
from django_nepkit.utils import (
|
|
7
12
|
try_parse_nepali_date,
|
|
8
13
|
try_parse_nepali_datetime,
|
|
14
|
+
format_nepali_currency,
|
|
9
15
|
)
|
|
16
|
+
from django_nepkit.utils import BS_DATE_FORMAT
|
|
10
17
|
|
|
11
18
|
|
|
12
|
-
def
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
Args:
|
|
17
|
-
date_value: A nepalidate object or string in YYYY-MM-DD format
|
|
18
|
-
format_string: strftime format string (default: '%B %d, %Y')
|
|
19
|
-
%B = Full month name (Baishak, Jestha, etc.)
|
|
20
|
-
%b = Short month name
|
|
21
|
-
%d = Day of month
|
|
22
|
-
%Y = Year
|
|
23
|
-
|
|
24
|
-
Returns:
|
|
25
|
-
Formatted date string with Nepali month names, or empty string if invalid
|
|
26
|
-
"""
|
|
27
|
-
if date_value is None:
|
|
19
|
+
def _format_nepali_common(value, try_parse_func, format_string, ne, cls_type):
|
|
20
|
+
"""Helper to format dates/times with optional Devanagari support."""
|
|
21
|
+
if value is None:
|
|
28
22
|
return ""
|
|
29
23
|
|
|
30
24
|
try:
|
|
31
|
-
parsed =
|
|
25
|
+
parsed = try_parse_func(value)
|
|
32
26
|
if parsed is not None:
|
|
27
|
+
if ne and hasattr(parsed, "strftime_ne"):
|
|
28
|
+
return parsed.strftime_ne(format_string)
|
|
33
29
|
return parsed.strftime(format_string)
|
|
34
|
-
if isinstance(
|
|
35
|
-
|
|
36
|
-
format_string
|
|
37
|
-
)
|
|
30
|
+
if isinstance(value, cls_type):
|
|
31
|
+
if ne and hasattr(value, "strftime_ne"):
|
|
32
|
+
return value.strftime_ne(format_string)
|
|
33
|
+
return value.strftime(format_string)
|
|
38
34
|
except (ValueError, TypeError, AttributeError):
|
|
39
35
|
pass
|
|
40
36
|
|
|
41
|
-
return str(
|
|
37
|
+
return str(value) if value else ""
|
|
42
38
|
|
|
43
39
|
|
|
44
|
-
def
|
|
40
|
+
def format_nepali_date(date_value, format_string="%B %d, %Y", ne=False):
|
|
45
41
|
"""
|
|
46
|
-
Format a
|
|
47
|
-
|
|
48
|
-
Default output uses **12-hour time with AM/PM**.
|
|
42
|
+
Format a nepalidate object with Nepali month names.
|
|
49
43
|
"""
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
try:
|
|
54
|
-
parsed = try_parse_nepali_datetime(datetime_value)
|
|
55
|
-
if parsed is not None:
|
|
56
|
-
return parsed.strftime(format_string)
|
|
57
|
-
if isinstance(datetime_value, nepalidatetime):
|
|
58
|
-
return datetime_value.strftime(
|
|
59
|
-
format_string
|
|
60
|
-
) # defensive; should be covered above
|
|
61
|
-
except (ValueError, TypeError, AttributeError):
|
|
62
|
-
pass
|
|
44
|
+
return _format_nepali_common(
|
|
45
|
+
date_value, try_parse_nepali_date, format_string, ne, nepalidate
|
|
46
|
+
)
|
|
63
47
|
|
|
64
|
-
return str(datetime_value) if datetime_value else ""
|
|
65
48
|
|
|
66
|
-
|
|
67
|
-
class NepaliDateFilter(admin.FieldListFilter):
|
|
49
|
+
def format_nepali_datetime(datetime_value, format_string=None, ne=False):
|
|
68
50
|
"""
|
|
69
|
-
|
|
51
|
+
Format a nepalidatetime object with Nepali month names.
|
|
70
52
|
"""
|
|
53
|
+
if format_string is None:
|
|
54
|
+
if nepkit_settings.TIME_FORMAT == 24:
|
|
55
|
+
format_string = "%B %d, %Y %H:%M"
|
|
56
|
+
else:
|
|
57
|
+
format_string = "%B %d, %Y %I:%M %p"
|
|
58
|
+
|
|
59
|
+
return _format_nepali_common(
|
|
60
|
+
datetime_value, try_parse_nepali_datetime, format_string, ne, nepalidatetime
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class BaseNepaliDateFilter(admin.FieldListFilter):
|
|
65
|
+
"""Base class for date filters (Year/Month)."""
|
|
71
66
|
|
|
72
67
|
def __init__(self, field, request, params, model, model_admin, field_path):
|
|
73
|
-
self.parameter_name = f"{field_path}
|
|
68
|
+
self.parameter_name = f"{field_path}_{self.suffix}"
|
|
74
69
|
super().__init__(field, request, params, model, model_admin, field_path)
|
|
75
|
-
self.title = _("Nepali Date (Year)")
|
|
76
70
|
|
|
77
71
|
def expected_parameters(self):
|
|
78
72
|
return [self.parameter_name]
|
|
@@ -83,40 +77,85 @@ class NepaliDateFilter(admin.FieldListFilter):
|
|
|
83
77
|
"query_string": changelist.get_query_string(remove=[self.parameter_name]),
|
|
84
78
|
"display": _("All"),
|
|
85
79
|
}
|
|
86
|
-
|
|
87
|
-
for year in range(current_year - 10, current_year + 2):
|
|
80
|
+
for value, display in self.get_filter_options():
|
|
88
81
|
yield {
|
|
89
|
-
"selected": self.used_parameters.get(self.parameter_name) == str(
|
|
82
|
+
"selected": self.used_parameters.get(self.parameter_name) == str(value),
|
|
90
83
|
"query_string": changelist.get_query_string(
|
|
91
|
-
{self.parameter_name: str(
|
|
84
|
+
{self.parameter_name: str(value)}
|
|
92
85
|
),
|
|
93
|
-
"display":
|
|
86
|
+
"display": display,
|
|
94
87
|
}
|
|
95
88
|
|
|
96
89
|
def queryset(self, request, queryset):
|
|
97
90
|
value = self.used_parameters.get(self.parameter_name)
|
|
98
91
|
if value:
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
start_date_bs = nepalidate(year, 1, 1)
|
|
102
|
-
# Find last day of the year. Some BS years end on the 30th,
|
|
103
|
-
# so we try 31 first and then fall back to 30 if that date
|
|
104
|
-
# is not valid.
|
|
105
|
-
try:
|
|
106
|
-
end_date_bs = nepalidate(year, 12, 31)
|
|
107
|
-
except ValueError:
|
|
108
|
-
end_date_bs = nepalidate(year, 12, 30)
|
|
92
|
+
return self.apply_filter(queryset, value)
|
|
93
|
+
return queryset
|
|
109
94
|
|
|
110
|
-
|
|
111
|
-
|
|
95
|
+
def get_filter_options(self):
|
|
96
|
+
raise NotImplementedError
|
|
112
97
|
|
|
98
|
+
def apply_filter(self, queryset, value):
|
|
99
|
+
raise NotImplementedError
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class NepaliDateFilter(BaseNepaliDateFilter):
|
|
103
|
+
"""Filter by Nepali Year (e.g., 2080)."""
|
|
104
|
+
|
|
105
|
+
suffix = "bs_year"
|
|
106
|
+
title = _("Nepali Date (Year)")
|
|
107
|
+
|
|
108
|
+
def get_filter_options(self):
|
|
109
|
+
current_year = nepalidate.today().year
|
|
110
|
+
return [(y, str(y)) for y in range(current_year - 10, current_year + 2)]
|
|
111
|
+
|
|
112
|
+
def apply_filter(self, queryset, value):
|
|
113
|
+
if BS_DATE_FORMAT.startswith("%Y"):
|
|
114
|
+
separator = BS_DATE_FORMAT[2] if len(BS_DATE_FORMAT) > 2 else "-"
|
|
113
115
|
return queryset.filter(
|
|
114
|
-
**{f"{self.field_path}
|
|
116
|
+
**{f"{self.field_path}__startswith": f"{value}{separator}"}
|
|
115
117
|
)
|
|
116
|
-
|
|
118
|
+
|
|
119
|
+
return queryset.filter(**{f"{self.field_path}__icontains": f"{value}"})
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class NepaliMonthFilter(BaseNepaliDateFilter):
|
|
123
|
+
"""Filter by Nepali Month (e.g., Baisakh)."""
|
|
124
|
+
|
|
125
|
+
suffix = "bs_month"
|
|
126
|
+
title = _("Nepali Date (Month)")
|
|
127
|
+
|
|
128
|
+
def get_filter_options(self):
|
|
129
|
+
ne = nepkit_settings.DEFAULT_LANGUAGE == "ne"
|
|
130
|
+
names = [
|
|
131
|
+
("बैशाख", "Baisakh"),
|
|
132
|
+
("जेठ", "Jestha"),
|
|
133
|
+
("असार", "Ashad"),
|
|
134
|
+
("साउन", "Shrawan"),
|
|
135
|
+
("भदौ", "Bhadra"),
|
|
136
|
+
("असोज", "Ashwin"),
|
|
137
|
+
("कात्तिक", "Kartik"),
|
|
138
|
+
("मंसिर", "Mangsir"),
|
|
139
|
+
("पुष", "Poush"),
|
|
140
|
+
("माघ", "Magh"),
|
|
141
|
+
("फागुन", "Falgun"),
|
|
142
|
+
("चैत", "Chaitra"),
|
|
143
|
+
]
|
|
144
|
+
return [(f"{i:02d}", n[0] if ne else n[1]) for i, n in enumerate(names, 1)]
|
|
145
|
+
|
|
146
|
+
def apply_filter(self, queryset, value):
|
|
147
|
+
from django_nepkit.utils import BS_DATE_FORMAT
|
|
148
|
+
|
|
149
|
+
if BS_DATE_FORMAT == "%Y-%m-%d":
|
|
150
|
+
return queryset.filter(**{f"{self.field_path}__contains": f"-{value}-"})
|
|
151
|
+
|
|
152
|
+
separator = BS_DATE_FORMAT[2] if len(BS_DATE_FORMAT) > 2 else "-"
|
|
153
|
+
return queryset.filter(
|
|
154
|
+
**{f"{self.field_path}__contains": f"{separator}{value}{separator}"}
|
|
155
|
+
)
|
|
117
156
|
|
|
118
157
|
|
|
119
|
-
#
|
|
158
|
+
# Standard filter for any NepaliDateField in Admin
|
|
120
159
|
admin.FieldListFilter.register(
|
|
121
160
|
lambda f: isinstance(f, NepaliDateField),
|
|
122
161
|
NepaliDateFilter,
|
|
@@ -125,65 +164,176 @@ admin.FieldListFilter.register(
|
|
|
125
164
|
|
|
126
165
|
|
|
127
166
|
class NepaliAdminMixin:
|
|
128
|
-
"""
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
167
|
+
"""Provides date formatting tools for Admin classes."""
|
|
168
|
+
|
|
169
|
+
def _get_field_ne_setting(self, field_name):
|
|
170
|
+
"""
|
|
171
|
+
Get the 'ne' setting from a model field.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
field_name: Name of the field in the model
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
True if field has ne=True, False otherwise
|
|
178
|
+
"""
|
|
179
|
+
if not hasattr(self, "model"):
|
|
180
|
+
return False
|
|
132
181
|
|
|
133
|
-
|
|
182
|
+
try:
|
|
183
|
+
field = self.model._meta.get_field(field_name)
|
|
184
|
+
if hasattr(field, "ne"):
|
|
185
|
+
return field.ne
|
|
186
|
+
except (AttributeError, LookupError):
|
|
187
|
+
pass
|
|
188
|
+
|
|
189
|
+
return False
|
|
190
|
+
|
|
191
|
+
def format_nepali_date(
|
|
192
|
+
self, date_value, format_string="%B %d, %Y", ne=None, field_name=None
|
|
193
|
+
):
|
|
134
194
|
"""
|
|
135
195
|
Format a nepalidate object with Nepali month names.
|
|
136
196
|
Available as a method on admin classes using this mixin.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
date_value: A nepalidate object or string
|
|
200
|
+
format_string: strftime format string
|
|
201
|
+
ne: If True, format using Devanagari script. If None, auto-detect from field or global settings (default: None)
|
|
202
|
+
field_name: Name of the field to auto-detect 'ne' setting from (optional)
|
|
137
203
|
"""
|
|
138
|
-
|
|
204
|
+
if ne is None and field_name:
|
|
205
|
+
ne = self._get_field_ne_setting(field_name)
|
|
206
|
+
elif ne is None:
|
|
207
|
+
ne = nepkit_settings.DEFAULT_LANGUAGE == "ne"
|
|
208
|
+
|
|
209
|
+
return format_nepali_date(date_value, format_string, ne=ne)
|
|
139
210
|
|
|
140
211
|
def format_nepali_datetime(
|
|
141
|
-
self,
|
|
212
|
+
self,
|
|
213
|
+
datetime_value,
|
|
214
|
+
format_string=None,
|
|
215
|
+
ne=None,
|
|
216
|
+
field_name=None,
|
|
142
217
|
):
|
|
143
|
-
|
|
218
|
+
"""
|
|
219
|
+
Format a nepalidatetime object with Nepali month names.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
datetime_value: A nepalidatetime object or string
|
|
223
|
+
format_string: strftime format string
|
|
224
|
+
ne: If True, format using Devanagari script. If None, auto-detect from field or global settings (default: None)
|
|
225
|
+
field_name: Name of the field to auto-detect 'ne' setting from (optional)
|
|
226
|
+
"""
|
|
227
|
+
if ne is None and field_name:
|
|
228
|
+
ne = self._get_field_ne_setting(field_name)
|
|
229
|
+
elif ne is None:
|
|
230
|
+
ne = nepkit_settings.DEFAULT_LANGUAGE == "ne"
|
|
231
|
+
|
|
232
|
+
return format_nepali_datetime(datetime_value, format_string, ne=ne)
|
|
233
|
+
|
|
234
|
+
def format_nepali_currency(self, value, currency_symbol="Rs.", ne=False, **kwargs):
|
|
235
|
+
"""
|
|
236
|
+
Format a number with Nepali-style commas.
|
|
237
|
+
Available as a method on admin classes using this mixin.
|
|
238
|
+
"""
|
|
239
|
+
return format_nepali_currency(value, currency_symbol=currency_symbol, ne=ne)
|
|
144
240
|
|
|
145
241
|
|
|
146
242
|
class NepaliModelAdmin(NepaliAdminMixin, admin.ModelAdmin):
|
|
147
243
|
"""
|
|
148
|
-
|
|
149
|
-
Use this instead of admin.ModelAdmin to have format_nepali_date available.
|
|
244
|
+
Standard Admin class that automatically formats Nepali dates in lists.
|
|
150
245
|
|
|
151
246
|
Example:
|
|
152
247
|
from django_nepkit import NepaliModelAdmin, NepaliDateFilter
|
|
153
248
|
|
|
154
249
|
@admin.register(MyModel)
|
|
155
250
|
class MyModelAdmin(NepaliModelAdmin):
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
def display_date(self, obj):
|
|
159
|
-
return self.format_nepali_date(obj.date_field)
|
|
251
|
+
list_display = ("name", "birth_date", "created_at") # auto-formatted
|
|
252
|
+
list_filter = (("birth_date", NepaliDateFilter),)
|
|
160
253
|
"""
|
|
161
254
|
|
|
162
|
-
# Make
|
|
255
|
+
# Make filters available as class attributes
|
|
163
256
|
NepaliDateFilter = NepaliDateFilter
|
|
257
|
+
NepaliMonthFilter = NepaliMonthFilter
|
|
258
|
+
|
|
259
|
+
def _make_nepali_display(self, field_name, formatter_method):
|
|
260
|
+
"""Helper to create display columns for Nepali dates."""
|
|
261
|
+
admin_instance = self
|
|
262
|
+
try:
|
|
263
|
+
field = self.model._meta.get_field(field_name)
|
|
264
|
+
short_description = getattr(
|
|
265
|
+
field, "verbose_name", field_name.replace("_", " ").title()
|
|
266
|
+
)
|
|
267
|
+
except Exception:
|
|
268
|
+
short_description = field_name.replace("_", " ").title()
|
|
269
|
+
|
|
270
|
+
def display(obj):
|
|
271
|
+
val = getattr(obj, field_name, None)
|
|
272
|
+
if val is None:
|
|
273
|
+
return admin_instance.get_empty_value_display()
|
|
274
|
+
# Call the passed formatter method (bound to self)
|
|
275
|
+
return formatter_method(val, field_name=field_name)
|
|
276
|
+
|
|
277
|
+
display.short_description = short_description
|
|
278
|
+
display.admin_order_field = field_name
|
|
279
|
+
return display
|
|
280
|
+
|
|
281
|
+
def _make_nepali_date_display(self, field_name):
|
|
282
|
+
return self._make_nepali_display(field_name, self.format_nepali_date)
|
|
283
|
+
|
|
284
|
+
def _make_nepali_datetime_display(self, field_name):
|
|
285
|
+
return self._make_nepali_display(field_name, self.format_nepali_datetime)
|
|
286
|
+
|
|
287
|
+
def _make_nepali_currency_display(self, field_name):
|
|
288
|
+
return self._make_nepali_display(field_name, self.format_nepali_currency)
|
|
289
|
+
|
|
290
|
+
def get_list_display(self, request):
|
|
291
|
+
list_display = super().get_list_display(request)
|
|
292
|
+
result = []
|
|
293
|
+
for item in list_display:
|
|
294
|
+
if not isinstance(item, str):
|
|
295
|
+
result.append(item)
|
|
296
|
+
continue
|
|
297
|
+
try:
|
|
298
|
+
field = self.model._meta.get_field(item)
|
|
299
|
+
if isinstance(field, NepaliDateField):
|
|
300
|
+
result.append(self._make_nepali_date_display(item))
|
|
301
|
+
continue
|
|
302
|
+
if isinstance(field, NepaliDateTimeField):
|
|
303
|
+
result.append(self._make_nepali_datetime_display(item))
|
|
304
|
+
continue
|
|
305
|
+
if isinstance(field, NepaliCurrencyField):
|
|
306
|
+
result.append(self._make_nepali_currency_display(item))
|
|
307
|
+
continue
|
|
308
|
+
except Exception:
|
|
309
|
+
pass
|
|
310
|
+
result.append(item)
|
|
311
|
+
return result
|
|
164
312
|
|
|
165
|
-
# Ensure admin forms render Nepali fields with the proper widget,
|
|
166
|
-
# even if a project doesn't provide custom ModelForms.
|
|
167
313
|
def formfield_for_dbfield(self, db_field, request, **kwargs):
|
|
168
|
-
"""
|
|
169
|
-
Force Nepali widgets in Django admin without requiring user forms.
|
|
170
|
-
"""
|
|
314
|
+
"""Automatically use NepaliDatePicker in the admin form."""
|
|
171
315
|
try:
|
|
172
316
|
from django_nepkit.models import NepaliDateField, NepaliDateTimeField
|
|
173
317
|
from django_nepkit.widgets import NepaliDatePickerWidget
|
|
174
318
|
except Exception:
|
|
175
319
|
return super().formfield_for_dbfield(db_field, request, **kwargs)
|
|
176
320
|
|
|
177
|
-
if
|
|
178
|
-
|
|
321
|
+
if (
|
|
322
|
+
isinstance(db_field, (NepaliDateField, NepaliDateTimeField))
|
|
323
|
+
and nepkit_settings.ADMIN_DATEPICKER
|
|
324
|
+
):
|
|
325
|
+
# Pass ne/en parameters from field to widget if they exist
|
|
326
|
+
widget_kwargs = {}
|
|
327
|
+
if hasattr(db_field, "ne"):
|
|
328
|
+
widget_kwargs["ne"] = db_field.ne
|
|
329
|
+
if hasattr(db_field, "en"):
|
|
330
|
+
widget_kwargs["en"] = db_field.en
|
|
331
|
+
kwargs.setdefault("widget", NepaliDatePickerWidget(**widget_kwargs))
|
|
179
332
|
|
|
180
333
|
return super().formfield_for_dbfield(db_field, request, **kwargs)
|
|
181
334
|
|
|
182
335
|
class Media:
|
|
183
|
-
"""
|
|
184
|
-
Django admin ships jQuery as `django.jQuery` (not `window.jQuery`).
|
|
185
|
-
The Nepali date picker library expects a global `jQuery`, so we bridge it.
|
|
186
|
-
"""
|
|
336
|
+
"""Loads the Nepali Datepicker and bridging scripts."""
|
|
187
337
|
|
|
188
338
|
css = {
|
|
189
339
|
"all": (
|
|
@@ -201,9 +351,9 @@ class NepaliModelAdmin(NepaliAdminMixin, admin.ModelAdmin):
|
|
|
201
351
|
)
|
|
202
352
|
|
|
203
353
|
|
|
204
|
-
# Exporting for easy usage
|
|
205
354
|
__all__ = [
|
|
206
355
|
"NepaliDateFilter",
|
|
356
|
+
"NepaliMonthFilter",
|
|
207
357
|
"format_nepali_date",
|
|
208
358
|
"format_nepali_datetime",
|
|
209
359
|
"NepaliAdminMixin",
|
django_nepkit/conf.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from django.conf import settings
|
|
2
|
+
|
|
3
|
+
DEFAULTS = {
|
|
4
|
+
"DEFAULT_LANGUAGE": "en",
|
|
5
|
+
"DATE_INPUT_FORMATS": ["%Y-%m-%d", "%d/%m/%Y", "%d-%m-%Y"],
|
|
6
|
+
"ADMIN_DATEPICKER": True,
|
|
7
|
+
"TIME_FORMAT": 12,
|
|
8
|
+
"BS_DATE_FORMAT": "%Y-%m-%d",
|
|
9
|
+
"BS_DATETIME_FORMAT": "%Y-%m-%d %H:%M:%S",
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class NepkitSettings:
|
|
14
|
+
"""Handles the global NEPKIT settings from your settings.py."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, user_settings=None, defaults=None):
|
|
17
|
+
self._user_settings = user_settings or {}
|
|
18
|
+
self.defaults = defaults or DEFAULTS
|
|
19
|
+
|
|
20
|
+
def __getattr__(self, attr):
|
|
21
|
+
if attr not in self.defaults:
|
|
22
|
+
raise AttributeError(f"Invalid NEPKIT setting: '{attr}'")
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
# Check if the user has a custom setting
|
|
26
|
+
val = self._user_settings[attr]
|
|
27
|
+
except KeyError:
|
|
28
|
+
# Use default value if not set
|
|
29
|
+
val = self.defaults[attr]
|
|
30
|
+
|
|
31
|
+
return val
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
nepkit_settings = NepkitSettings(getattr(settings, "NEPKIT", {}), DEFAULTS)
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Constants for django-nepkit package.
|
|
3
|
+
Contains hardcoded values, word mappings, and configuration data.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# Nepali number words mapping (0-99)
|
|
7
|
+
NEPALI_ONES = [
|
|
8
|
+
"",
|
|
9
|
+
"एक",
|
|
10
|
+
"दुई",
|
|
11
|
+
"तीन",
|
|
12
|
+
"चार",
|
|
13
|
+
"पाँच",
|
|
14
|
+
"छ",
|
|
15
|
+
"सात",
|
|
16
|
+
"आठ",
|
|
17
|
+
"नौ",
|
|
18
|
+
"दश",
|
|
19
|
+
"एघार",
|
|
20
|
+
"बाह्र",
|
|
21
|
+
"तेह्र",
|
|
22
|
+
"चौध",
|
|
23
|
+
"पन्ध्र",
|
|
24
|
+
"सोह्र",
|
|
25
|
+
"सत्र",
|
|
26
|
+
"अठार",
|
|
27
|
+
"उन्नाइस",
|
|
28
|
+
"बीस",
|
|
29
|
+
"एकाइस",
|
|
30
|
+
"बाइस",
|
|
31
|
+
"तेईस",
|
|
32
|
+
"चौबीस",
|
|
33
|
+
"पच्चीस",
|
|
34
|
+
"छब्बीस",
|
|
35
|
+
"सत्ताइस",
|
|
36
|
+
"अठाइस",
|
|
37
|
+
"उनन्तीस",
|
|
38
|
+
"तीस",
|
|
39
|
+
"एकतीस",
|
|
40
|
+
"बत्तीस",
|
|
41
|
+
"तेत्तीस",
|
|
42
|
+
"चौंतीस",
|
|
43
|
+
"पैंतीस",
|
|
44
|
+
"छत्तीस",
|
|
45
|
+
"सैंतीस",
|
|
46
|
+
"अठतीस",
|
|
47
|
+
"उनन्चालीस",
|
|
48
|
+
"चालीस",
|
|
49
|
+
"एकचालीस",
|
|
50
|
+
"बयालीस",
|
|
51
|
+
"त्रिचालीस",
|
|
52
|
+
"चवालीस",
|
|
53
|
+
"पैंतालीस",
|
|
54
|
+
"छयालीस",
|
|
55
|
+
"सत्तालीस",
|
|
56
|
+
"अठचालीस",
|
|
57
|
+
"उनन्पचास",
|
|
58
|
+
"पचास",
|
|
59
|
+
"एकाउन्न",
|
|
60
|
+
"बाउन्न",
|
|
61
|
+
"त्रिपन्न",
|
|
62
|
+
"चउन्न",
|
|
63
|
+
"पचपन्न",
|
|
64
|
+
"छपन्न",
|
|
65
|
+
"सन्ताउन्न",
|
|
66
|
+
"अन्ठाउन्न",
|
|
67
|
+
"उनन्साठी",
|
|
68
|
+
"साठी",
|
|
69
|
+
"एकसाठी",
|
|
70
|
+
"बासट्ठी",
|
|
71
|
+
"त्रिसट्ठी",
|
|
72
|
+
"चौसट्ठी",
|
|
73
|
+
"पैंसट्ठी",
|
|
74
|
+
"छयसट्ठी",
|
|
75
|
+
"सतसट्ठी",
|
|
76
|
+
"अठसट्ठी",
|
|
77
|
+
"उनन्सत्तरी",
|
|
78
|
+
"सत्तरी",
|
|
79
|
+
"एकहत्तर",
|
|
80
|
+
"बाहत्तर",
|
|
81
|
+
"त्रिहत्तर",
|
|
82
|
+
"चौरहत्तर",
|
|
83
|
+
"पचहत्तर",
|
|
84
|
+
"छयहत्तर",
|
|
85
|
+
"सतहत्तर",
|
|
86
|
+
"अठहत्तर",
|
|
87
|
+
"उनन्असी",
|
|
88
|
+
"असी",
|
|
89
|
+
"एकासी",
|
|
90
|
+
"बयासी",
|
|
91
|
+
"त्रियासी",
|
|
92
|
+
"चौरासी",
|
|
93
|
+
"पचासी",
|
|
94
|
+
"छयासी",
|
|
95
|
+
"सतासी",
|
|
96
|
+
"अठासी",
|
|
97
|
+
"उनन्नब्बे",
|
|
98
|
+
"नब्बे",
|
|
99
|
+
"एकानब्बे",
|
|
100
|
+
"बयानब्बे",
|
|
101
|
+
"त्रियानब्बे",
|
|
102
|
+
"चौरानब्बे",
|
|
103
|
+
"पञ्चानब्बे",
|
|
104
|
+
"छ्यानब्बे",
|
|
105
|
+
"सन्तानब्बे",
|
|
106
|
+
"अन्ठानब्बे",
|
|
107
|
+
"उनन्सय",
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
# Nepali number units and their corresponding names
|
|
111
|
+
NEPALI_UNITS = [
|
|
112
|
+
("", ""),
|
|
113
|
+
(100, "सय"),
|
|
114
|
+
(1000, "हजार"),
|
|
115
|
+
(100000, "लाख"),
|
|
116
|
+
(10000000, "करोड"),
|
|
117
|
+
(1000000000, "अरब"),
|
|
118
|
+
(100000000000, "खरब"),
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
# Placeholder text for location selects
|
|
122
|
+
PLACEHOLDERS = {
|
|
123
|
+
"province": {"ne": "प्रदेश छान्नुहोस्", "en": "Select Province"},
|
|
124
|
+
"district": {"ne": "जिल्ला छान्नुहोस्", "en": "Select District"},
|
|
125
|
+
"municipality": {"ne": "नगरपालिका छान्नुहोस्", "en": "Select Municipality"},
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
# Internal parameters to exclude from fallback logic
|
|
129
|
+
INTERNAL_PARAMS = ["ne", "en", "html"]
|