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.
Files changed (39) hide show
  1. django_nepkit/__init__.py +20 -0
  2. django_nepkit/admin.py +243 -93
  3. django_nepkit/conf.py +34 -0
  4. django_nepkit/constants.py +129 -0
  5. django_nepkit/filters.py +113 -0
  6. django_nepkit/forms.py +9 -9
  7. django_nepkit/lang_utils.py +52 -0
  8. django_nepkit/models.py +138 -161
  9. django_nepkit/serializers.py +127 -28
  10. django_nepkit/static/django_nepkit/js/address-chaining.js +129 -29
  11. django_nepkit/static/django_nepkit/js/nepal-data.js +1 -0
  12. django_nepkit/static/django_nepkit/js/nepali-datepicker-init.js +55 -46
  13. django_nepkit/utils.py +270 -46
  14. django_nepkit/validators.py +1 -1
  15. django_nepkit/views.py +127 -10
  16. django_nepkit/widgets.py +100 -31
  17. django_nepkit-0.2.1.dist-info/METADATA +308 -0
  18. django_nepkit-0.2.1.dist-info/RECORD +37 -0
  19. example/demo/admin.py +45 -21
  20. example/demo/models.py +41 -4
  21. example/demo/serializers.py +39 -0
  22. example/demo/urls.py +13 -2
  23. example/demo/views.py +125 -3
  24. example/example_project/settings.py +10 -0
  25. example/example_project/urls.py +1 -1
  26. example/manage.py +2 -2
  27. django_nepkit/templatetags/__init__.py +0 -0
  28. django_nepkit/templatetags/nepali.py +0 -74
  29. django_nepkit-0.1.0.dist-info/METADATA +0 -377
  30. django_nepkit-0.1.0.dist-info/RECORD +0 -39
  31. example/demo/migrations/0001_initial.py +0 -2113
  32. example/demo/migrations/0002_alter_person_phone_number.py +0 -18
  33. example/demo/migrations/0003_person_created_at_person_updated_at.py +0 -27
  34. example/demo/migrations/0004_alter_person_created_at_alter_person_updated_at.py +0 -23
  35. example/demo/migrations/0005_alter_person_created_at_alter_person_updated_at.py +0 -27
  36. example/demo/migrations/__init__.py +0 -0
  37. {django_nepkit-0.1.0.dist-info → django_nepkit-0.2.1.dist-info}/WHEEL +0 -0
  38. {django_nepkit-0.1.0.dist-info → django_nepkit-0.2.1.dist-info}/licenses/LICENSE +0 -0
  39. {django_nepkit-0.1.0.dist-info → django_nepkit-0.2.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,113 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from django.db.models import QuerySet
6
+
7
+ try:
8
+ from django_filters import rest_framework as filters
9
+ except ImportError as e:
10
+ raise ModuleNotFoundError(
11
+ "django-nepkit filter support is optional. Install with `django-nepkit[drf]` "
12
+ "to use `django_nepkit.filters`."
13
+ ) from e
14
+
15
+
16
+ class NepaliDateYearFilter(filters.NumberFilter):
17
+ """
18
+ A filter for `NepaliDateField` that allows filtering by Bikram Sambat Year.
19
+ Expects an integer year (e.g., 2080).
20
+ """
21
+
22
+ def filter(self, qs: QuerySet, value: Any) -> QuerySet:
23
+ if value:
24
+ from django_nepkit.utils import BS_DATE_FORMAT
25
+
26
+ # Find the date separator (e.g., '-' in '2080-01-01')
27
+ if BS_DATE_FORMAT.startswith("%Y"):
28
+ separator = BS_DATE_FORMAT[2] if len(BS_DATE_FORMAT) > 2 else "-"
29
+ return qs.filter(
30
+ **{f"{self.field_name}__startswith": f"{value}{separator}"}
31
+ )
32
+
33
+ # Fallback if the format is unusual
34
+ return qs.filter(**{f"{self.field_name}__icontains": str(value)})
35
+ return qs
36
+
37
+
38
+ class NepaliDateMonthFilter(filters.NumberFilter):
39
+ """
40
+ A filter for `NepaliDateField` that allows filtering by Bikram Sambat Month.
41
+ Expects an integer month (1-12).
42
+ """
43
+
44
+ def filter(self, qs: QuerySet, value: Any) -> QuerySet:
45
+ if value:
46
+ from django_nepkit.utils import BS_DATE_FORMAT
47
+
48
+ month_str = f"{int(value):02d}"
49
+
50
+ # Standard format: look for '-01-' for Baisakh
51
+ if BS_DATE_FORMAT == "%Y-%m-%d":
52
+ return qs.filter(**{f"{self.field_name}__contains": f"-{month_str}-"})
53
+
54
+ # Adaptive check for other separators
55
+ separator = BS_DATE_FORMAT[2] if len(BS_DATE_FORMAT) > 2 else "-"
56
+ return qs.filter(
57
+ **{f"{self.field_name}__contains": f"{separator}{month_str}{separator}"}
58
+ )
59
+ return qs
60
+
61
+
62
+ class NepaliDateRangeFilter(filters.CharFilter):
63
+ """
64
+ A filter for `NepaliDateField` that allows filtering by a range of BS dates.
65
+ Supports:
66
+ - "start,end" -> range
67
+ - "start," -> greater than or equal
68
+ - ",end" -> less than or equal
69
+ - "date" -> exact match
70
+ """
71
+
72
+ def filter(self, qs: QuerySet, value: Any) -> QuerySet:
73
+ if value:
74
+ parts = [p.strip() for p in str(value).split(",")]
75
+ if len(parts) == 1:
76
+ return qs.filter(**{self.field_name: parts[0]})
77
+ if len(parts) == 2:
78
+ if parts[0] and parts[1]:
79
+ return qs.filter(
80
+ **{f"{self.field_name}__range": (parts[0], parts[1])}
81
+ )
82
+ if parts[0]:
83
+ return qs.filter(**{f"{self.field_name}__gte": parts[0]})
84
+ if parts[1]:
85
+ return qs.filter(**{f"{self.field_name}__lte": parts[1]})
86
+ return qs
87
+
88
+
89
+ class NepaliCurrencyRangeFilter(filters.CharFilter):
90
+ """
91
+ A filter for `NepaliCurrencyField` that allows range filtering.
92
+ Supports:
93
+ - "min,max" -> range
94
+ - "min," -> greater than or equal
95
+ - ",max" -> less than or equal
96
+ - "value" -> exact match
97
+ """
98
+
99
+ def filter(self, qs: QuerySet, value: Any) -> QuerySet:
100
+ if value:
101
+ parts = [p.strip() for p in str(value).split(",")]
102
+ if len(parts) == 1:
103
+ return qs.filter(**{self.field_name: parts[0]})
104
+ if len(parts) == 2:
105
+ if parts[0] and parts[1]:
106
+ return qs.filter(
107
+ **{f"{self.field_name}__range": (parts[0], parts[1])}
108
+ )
109
+ if parts[0]:
110
+ return qs.filter(**{f"{self.field_name}__gte": parts[0]})
111
+ if parts[1]:
112
+ return qs.filter(**{f"{self.field_name}__lte": parts[1]})
113
+ return qs
django_nepkit/forms.py CHANGED
@@ -6,19 +6,18 @@ from nepali.datetime import nepalidate
6
6
 
7
7
  from django_nepkit.utils import try_parse_nepali_date
8
8
  from django_nepkit.validators import validate_nepali_phone_number
9
+ from django_nepkit.widgets import NepaliDatePickerWidget
9
10
 
10
11
 
11
12
  class NepaliDateFormField(forms.DateField):
12
- """
13
- A Django Form Field for Nepali Date (Bikram Sambat).
14
- """
15
-
16
- from .widgets import NepaliDatePickerWidget
13
+ """A form field for entering Nepali dates."""
17
14
 
18
15
  widget = NepaliDatePickerWidget
19
16
 
20
17
  def __init__(self, *args, **kwargs):
21
18
  kwargs.pop("max_length", None)
19
+ # Clean up arguments not needed for base Field
20
+ kwargs.pop("empty_value", None)
22
21
  super().__init__(*args, **kwargs)
23
22
 
24
23
  def to_python(self, value):
@@ -34,16 +33,17 @@ class NepaliDateFormField(forms.DateField):
34
33
  return parsed
35
34
  raise ValueError("Invalid BS date format")
36
35
  except Exception:
36
+ from django_nepkit.utils import BS_DATE_FORMAT
37
+
37
38
  raise forms.ValidationError(
38
- _("Enter a valid Nepali date in YYYY-MM-DD format."),
39
+ _("Enter a valid Nepali date in %(format)s format.")
40
+ % {"format": BS_DATE_FORMAT},
39
41
  code="invalid",
40
42
  )
41
43
 
42
44
 
43
45
  class NepaliPhoneNumberFormField(forms.CharField):
44
- """
45
- A Django Form Field for Nepali Phone Numbers.
46
- """
46
+ """A form field for entering Nepali phone numbers."""
47
47
 
48
48
  def __init__(self, *args, **kwargs):
49
49
  super().__init__(*args, **kwargs)
@@ -0,0 +1,52 @@
1
+ """
2
+ Language parameter utilities for django-nepkit.
3
+ Helper functions to resolve Nepali/English language parameters consistently.
4
+ """
5
+
6
+ from django_nepkit.conf import nepkit_settings
7
+
8
+
9
+ def resolve_language_params(ne=None, en=None, **kwargs):
10
+ """
11
+ Resolve language parameters with fallback to default settings.
12
+ """
13
+ default_lang = nepkit_settings.DEFAULT_LANGUAGE
14
+
15
+ # Extract from kwargs if provided
16
+ if ne is None and "ne" in kwargs:
17
+ ne = kwargs.get("ne")
18
+ if en is None and "en" in kwargs:
19
+ en = kwargs.get("en")
20
+
21
+ # Set defaults
22
+ if ne is None:
23
+ ne = default_lang == "ne"
24
+
25
+ # Handle en parameter logic
26
+ explicit_en = en is not None
27
+ if en is None:
28
+ en = not ne
29
+
30
+ # If ne is True and en wasn't explicitly set, en should be False
31
+ if ne and not explicit_en:
32
+ en = False
33
+
34
+ return ne, en
35
+
36
+
37
+ def pop_language_params(kwargs):
38
+ """
39
+ Pop ne/en parameters from kwargs dict and return resolved values.
40
+ """
41
+ default_lang = nepkit_settings.DEFAULT_LANGUAGE
42
+ ne = kwargs.pop("ne", default_lang == "ne")
43
+
44
+ explicit_en = "en" in kwargs
45
+ en_value = kwargs.pop("en", not ne)
46
+
47
+ if ne and not explicit_en:
48
+ en = False
49
+ else:
50
+ en = en_value
51
+
52
+ return ne, en
django_nepkit/models.py CHANGED
@@ -1,8 +1,11 @@
1
1
  from datetime import date as python_date
2
+ from datetime import datetime as python_datetime
2
3
 
3
4
  from django.db import models
5
+ from django.utils import timezone
4
6
  from django.utils.translation import gettext_lazy as _
5
7
  from nepali.datetime import nepalidate, nepalidatetime
8
+ from nepali.locations import districts, municipalities, provinces
6
9
 
7
10
  from django_nepkit.utils import (
8
11
  BS_DATE_FORMAT,
@@ -11,6 +14,43 @@ from django_nepkit.utils import (
11
14
  try_parse_nepali_datetime,
12
15
  )
13
16
  from django_nepkit.validators import validate_nepali_phone_number
17
+ from django_nepkit.widgets import (
18
+ DistrictSelectWidget,
19
+ MunicipalitySelectWidget,
20
+ NepaliDatePickerWidget,
21
+ ProvinceSelectWidget,
22
+ )
23
+ from django_nepkit.conf import nepkit_settings
24
+
25
+
26
+ class NepaliFieldMixin:
27
+ """Adds Nepali 'ne' and 'en' support to any field."""
28
+
29
+ def __init__(self, *args, **kwargs):
30
+ default_lang = nepkit_settings.DEFAULT_LANGUAGE
31
+ self.ne = kwargs.pop("ne", default_lang == "ne")
32
+
33
+ explicit_en = "en" in kwargs
34
+ en_value = kwargs.pop("en", not self.ne)
35
+
36
+ if self.ne and not explicit_en:
37
+ self.en = False
38
+ else:
39
+ self.en = en_value
40
+
41
+ self.htmx = kwargs.pop("htmx", False)
42
+
43
+ super().__init__(*args, **kwargs)
44
+
45
+ def deconstruct(self):
46
+ name, path, args, kwargs = super().deconstruct()
47
+ if self.ne:
48
+ kwargs["ne"] = True
49
+ if not self.en:
50
+ kwargs["en"] = False
51
+ if self.htmx:
52
+ kwargs["htmx"] = True
53
+ return name, path, args, kwargs
14
54
 
15
55
 
16
56
  class NepaliPhoneNumberField(models.CharField):
@@ -22,77 +62,89 @@ class NepaliPhoneNumberField(models.CharField):
22
62
  self.validators.append(validate_nepali_phone_number)
23
63
 
24
64
 
25
- class NepaliDateField(models.CharField):
26
- """
27
- A Django Model Field that stores Nepali (Bikram Sambat) Date.
28
- Internally it stores the date as BS string (YYYY-MM-DD) in the database.
29
- """
30
-
31
- description = _("Nepali Date (Bikram Sambat)")
65
+ class BaseNepaliBSField(NepaliFieldMixin, models.CharField):
66
+ """Base class for Nepali date and datetime fields."""
32
67
 
33
68
  def __init__(self, *args, **kwargs):
34
69
  self.auto_now = kwargs.pop("auto_now", False)
35
70
  self.auto_now_add = kwargs.pop("auto_now_add", False)
36
71
 
37
- # Match Django's DateField behavior
38
72
  if self.auto_now or self.auto_now_add:
39
73
  kwargs.setdefault("editable", False)
40
74
  kwargs.setdefault("blank", True)
41
75
 
42
- kwargs.setdefault("max_length", 10)
76
+ kwargs.setdefault("max_length", getattr(self, "default_max_length", 20))
43
77
  super().__init__(*args, **kwargs)
44
78
 
45
79
  def pre_save(self, model_instance, add):
46
80
  if self.auto_now or (self.auto_now_add and add):
47
- # Using nepalidate.today() to get current BS date.
48
- # This is BS-native as much as possible.
49
- value = nepalidate.today().strftime(BS_DATE_FORMAT)
81
+ now = timezone.now()
82
+ if timezone.is_aware(now):
83
+ now = timezone.localtime(now)
84
+
85
+ nepali_cls = getattr(self, "nepali_cls", nepalidate)
86
+ format_str = getattr(self, "format_str", BS_DATE_FORMAT)
87
+
88
+ value = (
89
+ nepali_cls.from_date(now).strftime(format_str)
90
+ if nepali_cls == nepalidate
91
+ else nepali_cls.from_datetime(now).strftime(format_str)
92
+ )
50
93
  setattr(model_instance, self.attname, value)
51
94
  return value
52
95
  return super().pre_save(model_instance, add)
53
96
 
54
97
  def from_db_value(self, value, expression, connection):
55
- parsed = try_parse_nepali_date(value)
98
+ parsed = self.parse_func(value)
56
99
  return parsed if parsed is not None else value
57
100
 
58
101
  def to_python(self, value):
59
- if value is None or isinstance(value, nepalidate):
102
+ if value is None or isinstance(value, self.nepali_cls):
60
103
  return value
61
- if isinstance(value, python_date):
62
- # If we MUST handle AD date object, we convert it to BS.
63
- # But we should prefer strings or nepalidate.
104
+ if isinstance(value, (python_date, python_datetime)):
64
105
  try:
65
- return nepalidate.from_date(value)
106
+ if isinstance(value, python_datetime) and timezone.is_aware(value):
107
+ value = timezone.localtime(value)
108
+ return (
109
+ self.nepali_cls.from_date(value)
110
+ if self.nepali_cls == nepalidate
111
+ else self.nepali_cls.from_datetime(value)
112
+ )
66
113
  except (ValueError, TypeError):
67
114
  return str(value)
68
115
  if isinstance(value, str):
69
- parsed = try_parse_nepali_date(value)
116
+ parsed = self.parse_func(value)
70
117
  return parsed if parsed is not None else value
71
118
  return super().to_python(value)
72
119
 
120
+ def _get_string_value(self, value):
121
+ if isinstance(value, (nepalidate, nepalidatetime)):
122
+ return value.strftime(self.format_str)
123
+ return value
124
+
73
125
  def validate(self, value, model_instance):
74
- if isinstance(value, nepalidate):
75
- value = value.strftime(BS_DATE_FORMAT)
76
- super().validate(value, model_instance)
126
+ super().validate(self._get_string_value(value), model_instance)
77
127
 
78
128
  def run_validators(self, value):
79
- if isinstance(value, nepalidate):
80
- value = value.strftime(BS_DATE_FORMAT)
81
- super().run_validators(value)
129
+ super().run_validators(self._get_string_value(value))
82
130
 
83
131
  def get_prep_value(self, value):
84
132
  if value is None:
85
133
  return value
86
- if isinstance(value, nepalidate):
87
- return value.strftime(BS_DATE_FORMAT)
88
- if isinstance(value, python_date):
134
+ if isinstance(value, self.nepali_cls):
135
+ return value.strftime(self.format_str)
136
+ if isinstance(value, (python_date, python_datetime)):
89
137
  try:
90
- return nepalidate.from_date(value).strftime(BS_DATE_FORMAT)
138
+ if isinstance(value, python_datetime) and timezone.is_aware(value):
139
+ value = timezone.localtime(value)
140
+ nepali_obj = (
141
+ self.nepali_cls.from_date(value)
142
+ if self.nepali_cls == nepalidate
143
+ else self.nepali_cls.from_datetime(value)
144
+ )
145
+ return nepali_obj.strftime(self.format_str)
91
146
  except (ValueError, TypeError):
92
147
  return str(value)
93
- if isinstance(value, str):
94
- return value
95
- # Fallback: convert to string
96
148
  return str(value)
97
149
 
98
150
  def deconstruct(self):
@@ -104,166 +156,91 @@ class NepaliDateField(models.CharField):
104
156
  return name, path, args, kwargs
105
157
 
106
158
  def formfield(self, **kwargs):
107
- from .forms import NepaliDateFormField
108
- from .widgets import NepaliDatePickerWidget
109
-
110
159
  defaults = {
111
- "form_class": NepaliDateFormField,
112
- "widget": NepaliDatePickerWidget,
160
+ "widget": NepaliDatePickerWidget(ne=self.ne, en=self.en),
113
161
  }
114
162
  defaults.update(kwargs)
115
163
  return super().formfield(**defaults)
116
164
 
117
165
 
118
- class NepaliTimeField(models.TimeField):
119
- """
120
- A Django Model Field for Time with Nepali localization support.
121
- Supports auto_now and auto_now_add like standard Django TimeField.
122
- """
123
-
124
- description = _("Nepali Time")
166
+ class NepaliDateField(BaseNepaliBSField):
167
+ description = _("Nepali Date (Bikram Sambat)")
168
+ default_max_length = 10
169
+ nepali_cls = nepalidate
170
+ format_str = BS_DATE_FORMAT
171
+ parse_func = staticmethod(try_parse_nepali_date)
125
172
 
173
+ def formfield(self, **kwargs):
174
+ # Import here to avoid circular dependency
175
+ from django_nepkit.forms import NepaliDateFormField
126
176
 
127
- class NepaliDateTimeField(models.CharField):
128
- """
129
- A Django Model Field that stores Nepali (Bikram Sambat) DateTime.
130
- Internally it stores the datetime as BS string (YYYY-MM-DD HH:MM:SS) in the database.
131
- """
177
+ kwargs.setdefault("form_class", NepaliDateFormField)
178
+ return super().formfield(**kwargs)
132
179
 
133
- description = _("Nepali DateTime (Bikram Sambat)")
134
180
 
135
- def __init__(self, *args, **kwargs):
136
- self.auto_now = kwargs.pop("auto_now", False)
137
- self.auto_now_add = kwargs.pop("auto_now_add", False)
181
+ class NepaliTimeField(NepaliFieldMixin, models.TimeField):
182
+ description = _("Nepali Time")
138
183
 
139
- # Match Django's DateTimeField behavior
140
- if self.auto_now or self.auto_now_add:
141
- kwargs.setdefault("editable", False)
142
- kwargs.setdefault("blank", True)
143
184
 
144
- kwargs.setdefault("max_length", 19) # YYYY-MM-DD HH:MM:SS
145
- super().__init__(*args, **kwargs)
185
+ class NepaliDateTimeField(BaseNepaliBSField):
186
+ description = _("Nepali DateTime (Bikram Sambat)")
187
+ default_max_length = 19
188
+ nepali_cls = nepalidatetime
189
+ format_str = BS_DATETIME_FORMAT
190
+ parse_func = staticmethod(try_parse_nepali_datetime)
146
191
 
147
- def pre_save(self, model_instance, add):
148
- if self.auto_now or (self.auto_now_add and add):
149
- # Using nepalidatetime.now() to get current BS datetime
150
- value = nepalidatetime.now().strftime(BS_DATETIME_FORMAT)
151
- setattr(model_instance, self.attname, value)
152
- return value
153
- return super().pre_save(model_instance, add)
154
192
 
155
- def from_db_value(self, value, expression, connection):
156
- parsed = try_parse_nepali_datetime(value)
157
- return parsed if parsed is not None else value
193
+ class BaseLocationField(NepaliFieldMixin, models.CharField):
194
+ """Base class for Province, District, and Municipality fields."""
158
195
 
159
- def to_python(self, value):
160
- if value is None or isinstance(value, nepalidatetime):
161
- return value
162
- if isinstance(value, str):
163
- parsed = try_parse_nepali_datetime(value)
164
- return parsed if parsed is not None else value
165
- return super().to_python(value)
196
+ def __init__(self, *args, **kwargs):
197
+ kwargs.setdefault("max_length", 100)
166
198
 
167
- def validate(self, value, model_instance):
168
- if isinstance(value, nepalidatetime):
169
- value = value.strftime(BS_DATETIME_FORMAT)
170
- super().validate(value, model_instance)
199
+ default_lang = nepkit_settings.DEFAULT_LANGUAGE
200
+ ne = kwargs.get("ne", default_lang == "ne")
171
201
 
172
- def run_validators(self, value):
173
- if isinstance(value, nepalidatetime):
174
- value = value.strftime(BS_DATETIME_FORMAT)
175
- super().run_validators(value)
202
+ # Load choices from the library (provinces, districts, etc.)
203
+ kwargs.setdefault("choices", self.get_choices_from_source(ne))
204
+ super().__init__(*args, **kwargs)
176
205
 
177
- def get_prep_value(self, value):
178
- if value is None:
179
- return value
180
- if isinstance(value, nepalidatetime):
181
- return value.strftime(BS_DATETIME_FORMAT)
182
- if isinstance(value, str):
183
- return value
184
- # Fallback: convert to string
185
- return str(value)
206
+ def get_choices_from_source(self, ne):
207
+ source = getattr(self, "source", [])
208
+ return [(self._get_name(item, ne), self._get_name(item, ne)) for item in source]
186
209
 
187
- def deconstruct(self):
188
- name, path, args, kwargs = super().deconstruct()
189
- if self.auto_now:
190
- kwargs["auto_now"] = True
191
- if self.auto_now_add:
192
- kwargs["auto_now_add"] = True
193
- return name, path, args, kwargs
210
+ def _get_name(self, item, ne):
211
+ return getattr(item, "name_nepali", item.name) if ne else item.name
194
212
 
195
213
  def formfield(self, **kwargs):
196
- from .widgets import NepaliDatePickerWidget
197
-
198
- defaults = {
199
- "widget": NepaliDatePickerWidget,
200
- }
201
- defaults.update(kwargs)
202
- return super().formfield(**defaults)
203
-
214
+ widget_cls = getattr(self, "widget_class", None)
215
+ if widget_cls:
216
+ defaults = {"widget": widget_cls(ne=self.ne, en=self.en, htmx=self.htmx)}
217
+ defaults.update(kwargs)
218
+ return super(models.CharField, self).formfield(**defaults)
219
+ return super().formfield(**kwargs)
204
220
 
205
- class ProvinceField(models.CharField):
206
- """
207
- A Django Model Field for Nepali Provinces.
208
- """
209
221
 
222
+ class ProvinceField(BaseLocationField):
210
223
  description = _("Nepali Province")
224
+ source = provinces
225
+ widget_class = ProvinceSelectWidget
211
226
 
212
- def __init__(self, *args, **kwargs):
213
- from nepali.locations import provinces
214
-
215
- kwargs.setdefault("max_length", 100)
216
- kwargs.setdefault("choices", [(p.name, p.name) for p in provinces])
217
- super().__init__(*args, **kwargs)
218
-
219
- def formfield(self, **kwargs):
220
- from .widgets import ProvinceSelectWidget
221
-
222
- defaults = {"widget": ProvinceSelectWidget}
223
- defaults.update(kwargs)
224
- return super().formfield(**defaults)
225
-
226
-
227
- class DistrictField(models.CharField):
228
- """
229
- A Django Model Field for Nepali Districts.
230
- """
231
227
 
228
+ class DistrictField(BaseLocationField):
232
229
  description = _("Nepali District")
230
+ source = districts
231
+ widget_class = DistrictSelectWidget
233
232
 
234
- def __init__(self, *args, **kwargs):
235
- from nepali.locations import districts
236
-
237
- kwargs.setdefault("max_length", 100)
238
- kwargs.setdefault("choices", [(d.name, d.name) for d in districts])
239
- super().__init__(*args, **kwargs)
240
-
241
- def formfield(self, **kwargs):
242
- from .widgets import DistrictSelectWidget
243
-
244
- defaults = {"widget": DistrictSelectWidget}
245
- defaults.update(kwargs)
246
- return super().formfield(**defaults)
247
233
 
234
+ class MunicipalityField(BaseLocationField):
235
+ description = _("Nepali Municipality")
236
+ source = municipalities
237
+ widget_class = MunicipalitySelectWidget
248
238
 
249
- class MunicipalityField(models.CharField):
250
- """
251
- A Django Model Field for Nepali Municipalities.
252
- Includes Metropolitan, Sub-Metropolitan, Municipality, and Rural Municipality.
253
- """
254
239
 
255
- description = _("Nepali Municipality")
240
+ class NepaliCurrencyField(models.DecimalField):
241
+ description = _("Nepali Currency")
256
242
 
257
243
  def __init__(self, *args, **kwargs):
258
- from nepali.locations import municipalities
259
-
260
- kwargs.setdefault("max_length", 100)
261
- kwargs.setdefault("choices", [(m.name, m.name) for m in municipalities])
244
+ kwargs.setdefault("max_digits", 19)
245
+ kwargs.setdefault("decimal_places", 2)
262
246
  super().__init__(*args, **kwargs)
263
-
264
- def formfield(self, **kwargs):
265
- from .widgets import MunicipalitySelectWidget
266
-
267
- defaults = {"widget": MunicipalitySelectWidget}
268
- defaults.update(kwargs)
269
- return super().formfield(**defaults)