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,39 @@
1
+ from rest_framework import serializers
2
+ from django_nepkit.serializers import (
3
+ NepaliDateSerializerField,
4
+ NepaliCurrencySerializerField,
5
+ NepaliLocalizedSerializerMixin,
6
+ )
7
+ from .models import Person, Citizen, AuditedPerson, Transaction
8
+
9
+
10
+ class PersonSerializer(NepaliLocalizedSerializerMixin, serializers.ModelSerializer):
11
+ birth_date = NepaliDateSerializerField()
12
+
13
+ class Meta:
14
+ model = Person
15
+ fields = "__all__"
16
+
17
+
18
+ class TransactionSerializer(
19
+ NepaliLocalizedSerializerMixin, serializers.ModelSerializer
20
+ ):
21
+ amount_formatted = NepaliCurrencySerializerField(source="amount")
22
+
23
+ class Meta:
24
+ model = Transaction
25
+ fields = ["id", "title", "amount", "amount_formatted", "date"]
26
+
27
+
28
+ class CitizenSerializer(serializers.ModelSerializer):
29
+ class Meta:
30
+ model = Citizen
31
+ fields = "__all__"
32
+
33
+
34
+ class AuditedPersonSerializer(serializers.ModelSerializer):
35
+ birth_date = NepaliDateSerializerField()
36
+
37
+ class Meta:
38
+ model = AuditedPerson
39
+ fields = "__all__"
example/demo/urls.py CHANGED
@@ -1,9 +1,20 @@
1
- from django.urls import path
2
1
  from . import views
2
+ from rest_framework.routers import DefaultRouter
3
+ from django.urls import path
3
4
 
4
5
  app_name = "demo"
5
6
 
7
+ router = DefaultRouter()
8
+ router.register("api/persons", views.PersonViewSet, basename="person-api")
9
+ router.register("api/citizens", views.CitizenViewSet, basename="citizen-api")
10
+ router.register("api/audited", views.AuditedPersonViewSet, basename="audited-api")
11
+ router.register(
12
+ "api/transactions", views.TransactionViewSet, basename="transaction-api"
13
+ )
14
+
6
15
  urlpatterns = [
7
16
  path("", views.person_list, name="person-list"),
8
17
  path("add/", views.person_create, name="person-create"),
9
- ]
18
+ path("transactions/add/", views.transaction_create, name="transaction-create"),
19
+ path("normalize/", views.address_normalize_demo, name="address-normalize"),
20
+ ] + router.urls
example/demo/views.py CHANGED
@@ -1,6 +1,20 @@
1
- from django.shortcuts import render, redirect
2
- from .models import Person
3
1
  from django import forms
2
+ from django.shortcuts import render, redirect
3
+ from rest_framework import viewsets, filters as drf_filters
4
+ from django_filters import rest_framework as django_filters
5
+ from django_nepkit.filters import NepaliDateYearFilter, NepaliDateMonthFilter
6
+ from .models import Person, Citizen, AuditedPerson, Transaction
7
+ from .serializers import (
8
+ PersonSerializer,
9
+ CitizenSerializer,
10
+ AuditedPersonSerializer,
11
+ TransactionSerializer,
12
+ )
13
+ from django_nepkit.filters import (
14
+ NepaliCurrencyRangeFilter,
15
+ NepaliDateRangeFilter,
16
+ )
17
+ from django_nepkit.utils import normalize_address
4
18
 
5
19
 
6
20
  class PersonForm(forms.ModelForm):
@@ -9,16 +23,25 @@ class PersonForm(forms.ModelForm):
9
23
  fields = [
10
24
  "name",
11
25
  "birth_date",
26
+ "birth_date_ne",
12
27
  "phone_number",
13
28
  "province",
29
+ "province_ne",
14
30
  "district",
31
+ "district_ne",
15
32
  "municipality",
33
+ "municipality_ne",
16
34
  ]
17
35
 
18
36
 
19
37
  def person_list(request):
20
38
  persons = Person.objects.all()
21
- return render(request, "demo/person_list.html", {"persons": persons})
39
+ transactions = Transaction.objects.all()
40
+ return render(
41
+ request,
42
+ "demo/person_list.html",
43
+ {"persons": persons, "transactions": transactions},
44
+ )
22
45
 
23
46
 
24
47
  def person_create(request):
@@ -30,3 +53,102 @@ def person_create(request):
30
53
  else:
31
54
  form = PersonForm()
32
55
  return render(request, "demo/person_form.html", {"form": form})
56
+
57
+
58
+ class TransactionForm(forms.ModelForm):
59
+ class Meta:
60
+ model = Transaction
61
+ fields = ["title", "amount"]
62
+
63
+
64
+ def transaction_create(request):
65
+ if request.method == "POST":
66
+ form = TransactionForm(request.POST)
67
+ if form.is_valid():
68
+ form.save()
69
+ return redirect("demo:person-list")
70
+ else:
71
+ form = TransactionForm()
72
+ return render(
73
+ request, "demo/person_form.html", {"form": form, "title": "Add Transaction"}
74
+ )
75
+
76
+
77
+ # --- API Support (DRF) ---
78
+
79
+
80
+ class PersonViewSet(viewsets.ModelViewSet):
81
+ queryset = Person.objects.all()
82
+ serializer_class = PersonSerializer
83
+
84
+ # Sort and Search work automatically with BS date strings
85
+ filter_backends = [
86
+ django_filters.DjangoFilterBackend,
87
+ drf_filters.SearchFilter,
88
+ drf_filters.OrderingFilter,
89
+ ]
90
+
91
+ ordering_fields = ["birth_date", "created_at"]
92
+ search_fields = ["name", "birth_date", "phone_number"]
93
+
94
+ # Simple exact date filter
95
+ filterset_fields = {
96
+ "birth_date": ["exact"],
97
+ }
98
+
99
+ class PersonFilter(django_filters.FilterSet):
100
+ year = NepaliDateYearFilter(field_name="birth_date")
101
+ month = NepaliDateMonthFilter(field_name="birth_date")
102
+
103
+ class Meta:
104
+ model = Person
105
+ fields = ["province", "district"]
106
+
107
+ filterset_class = PersonFilter
108
+
109
+
110
+ class CitizenViewSet(viewsets.ModelViewSet):
111
+ queryset = Citizen.objects.all()
112
+ serializer_class = CitizenSerializer
113
+ filter_backends = [drf_filters.OrderingFilter]
114
+ ordering_fields = ["province", "district"]
115
+
116
+
117
+ class AuditedPersonViewSet(viewsets.ModelViewSet):
118
+ queryset = AuditedPerson.objects.all()
119
+ serializer_class = AuditedPersonSerializer
120
+ filter_backends = [drf_filters.SearchFilter, drf_filters.OrderingFilter]
121
+ search_fields = ["name", "birth_date"]
122
+ ordering_fields = ["created_at"]
123
+
124
+
125
+ class TransactionViewSet(viewsets.ModelViewSet):
126
+ queryset = Transaction.objects.all()
127
+ serializer_class = TransactionSerializer
128
+ filter_backends = [django_filters.DjangoFilterBackend]
129
+
130
+ class TransactionFilter(django_filters.FilterSet):
131
+ amount_range = NepaliCurrencyRangeFilter(field_name="amount")
132
+ date_range = NepaliDateRangeFilter(field_name="date")
133
+
134
+ class Meta:
135
+ model = Transaction
136
+ fields = ["title", "amount", "date"]
137
+
138
+ filterset_class = TransactionFilter
139
+
140
+
141
+ def address_normalize_demo(request):
142
+ address = request.GET.get("address", "")
143
+ result = None
144
+ if address:
145
+ result = normalize_address(address)
146
+
147
+ if request.headers.get("HX-Request") == "true":
148
+ return render(
149
+ request, "demo/address_normalize_partial.html", {"result": result}
150
+ )
151
+
152
+ return render(
153
+ request, "demo/address_normalize.html", {"address": address, "result": result}
154
+ )
@@ -14,6 +14,8 @@ INSTALLED_APPS = [
14
14
  "django.contrib.messages",
15
15
  "django.contrib.staticfiles",
16
16
  "django_nepkit",
17
+ "rest_framework",
18
+ "django_filters",
17
19
  "demo",
18
20
  ]
19
21
 
@@ -73,4 +75,12 @@ TIME_ZONE = "Asia/Kathmandu"
73
75
  USE_I18N = True
74
76
  USE_TZ = True
75
77
 
78
+ # django-nepkit settings
79
+ NEPKIT = {
80
+ "DEFAULT_LANGUAGE": "en", # Default to Devanagari for fields and widgets
81
+ "DATE_INPUT_FORMATS": ["%Y-%m-%d", "%d/%m/%Y", "%d-%m-%Y"],
82
+ "ADMIN_DATEPICKER": True,
83
+ "TIME_FORMAT": 12, # 12-hour format with AM/PM
84
+ }
85
+
76
86
  STATIC_URL = "static/"
@@ -3,6 +3,6 @@ from django.urls import include, path
3
3
 
4
4
  urlpatterns = [
5
5
  path("admin/", admin.site.urls),
6
- path("nepkit/", include("django_nepkit.urls")),
6
+ # path("nepkit/", include("django_nepkit.urls")),
7
7
  path("", include("demo.urls")),
8
8
  ]
example/manage.py CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env python
2
- """Django's command-line utility for administrative tasks."""
2
+ """Django utility for running commands."""
3
3
 
4
4
  import os
5
5
  import sys
6
6
 
7
7
 
8
8
  def main():
9
- """Run administrative tasks."""
9
+ """Main entry point for Django commands."""
10
10
  sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
11
11
  os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example_project.settings")
12
12
  try:
File without changes
@@ -1,74 +0,0 @@
1
- from django import template
2
- from nepali.datetime import nepalidate, nepalihumanize
3
- from nepali.number import nepalinumber
4
- import datetime
5
-
6
- register = template.Library()
7
-
8
-
9
- def _coerce_ad_date_to_bs(value):
10
- """
11
- Internal helper: if value is AD date/datetime, convert to `nepalidate`.
12
- Does NOT attempt to parse strings (keeps template behavior minimal).
13
- """
14
- if isinstance(value, (datetime.datetime, datetime.date)):
15
- return nepalidate.from_date(value)
16
- return value
17
-
18
-
19
- @register.filter
20
- def nepali_date(value, format_str="%Y-%m-%d"):
21
- """
22
- Formats a date or datetime object into a Nepali date string.
23
- """
24
- if value is None:
25
- return ""
26
-
27
- value = _coerce_ad_date_to_bs(value)
28
-
29
- if hasattr(value, "strftime"):
30
- return value.strftime(format_str)
31
- return value
32
-
33
-
34
- @register.filter
35
- def nepali_date_ne(value, format_str="%Y-%m-%d"):
36
- """
37
- Formats a date or datetime object into a Nepali date string (Devanagari).
38
- """
39
- if value is None:
40
- return ""
41
-
42
- value = _coerce_ad_date_to_bs(value)
43
-
44
- if hasattr(value, "strftime_ne"):
45
- return value.strftime_ne(format_str)
46
- return value
47
-
48
-
49
- @register.filter
50
- def nepali_number(value):
51
- """
52
- Converts a number to Devanagari.
53
- """
54
- if value is None:
55
- return ""
56
- return nepalinumber(value).str_ne()
57
-
58
-
59
- @register.filter
60
- def nepali_humanize(value, threshold=None, format_str=None):
61
- """
62
- Returns a human-readable "time ago" string in Nepali.
63
- """
64
- if value is None:
65
- return ""
66
-
67
- # Threshold and format_str are optional
68
- kwargs = {}
69
- if threshold:
70
- kwargs["threshold"] = threshold
71
- if format_str:
72
- kwargs["format"] = format_str
73
-
74
- return nepalihumanize(value, **kwargs)