refactor: remove code redundancy and improve maintainability

- Extract duplicate view logic into reusable helper functions in views.py
- Move circular import from module level to method scope in models.py
- Create constants.py for centralized hardcoded values (Nepali words, placeholders)
- Simplify number_to_nepali_words function from 157 to 42 lines
- Refactor normalize_address with extracted helper functions
- Add lang_utils.py for consistent language parameter handling
- Reduce JavaScript duplication in address-chaining.js with helper functions
- Remove ~160+ lines of redundant code while preserving all logic
- All 79 tests passing, ruff linting passes
This commit is contained in:
sankalp committed 2026-02-05 20:49:26 +05:45
1 parent 74936ddabd
commit 718cff2951
8 files changed
+486 -286

No files matched your search

+18
View File
@@ -1,3 +1,21 @@
## V.2.1.0 — 2027-02-05
### ✨ Features
- upgrade nepali package to 1.2.0 and remove hardcoded Koshi Province mapping
### ♻️ Refactoring
- remove code redundancy and improve maintainability
- extract duplicate view logic into reusable helper functions in views.py
- create constants.py for centralized hardcoded values (Nepali words, placeholders)
- simplify number_to_nepali_words function from 157 to 42 lines
- refactor normalize_address with extracted helper functions
- add lang_utils.py for consistent language parameter handling
- reduce JavaScript duplication in address-chaining.js with helper functions
- move circular import from module level to method scope in models.py
- remove ~160+ lines of redundant code while preserving all logic
## V.2.0.0 — 2026-01-31
### ✨ Features
+33
View File
@@ -0,0 +1,33 @@
## 🚀 Release Unreleased — 2026-02-05
### ✨ Features
- implement address normalization and demo
- add Nepali currency support, number-to-words conversion, and REST API enhancements
- add Nepali currency field, number to words, and unicode helpers
- add Nepali currency field, number to words, and unicode helpers
- add English datepicker support and comprehensive documentation improvements
- implement HTMX support, DRF filters, and professionalized documentation
- implement zero-config address chaining and revamp documentation
- revamp localization support with Devanagari (BS) integration and documentation
### 📚 Documentation
- update
- added showcase
- updated readme
### 🧹 Other Changes
- feat:upgrade nepali package to 1.2.0 and remove hardcoded Koshi Province mapping
- feat:upgrade nepali package to 1.2.0 and remove hardcoded Koshi Province mapping
- bumped to v.0.2
- bumped to v.0.2
- fix
- update
- update todo
- added todo
- update
- updated workflow
- added workflow
- add comprehensive pytest test suite with 67% coverage
- update gitignore
- global project refinement, DRY consolidation, and documentation overhaul
- unwanted files
+129
View File
@@ -0,0 +1,129 @@
"""
Constants for django-nepkit package.
Contains hardcoded values, word mappings, and configuration data.
"""
# Nepali number words mapping (0-99)
NEPALI_ONES = [
"",
"एक",
"दुई",
"तीन",
"चार",
"पाँच",
"छ",
"सात",
"आठ",
"नौ",
"दश",
"एघार",
"बाह्र",
"तेह्र",
"चौध",
"पन्ध्र",
"सोह्र",
"सत्र",
"अठार",
"उन्नाइस",
"बीस",
"एकाइस",
"बाइस",
"तेईस",
"चौबीस",
"पच्चीस",
"छब्बीस",
"सत्ताइस",
"अठाइस",
"उनन्तीस",
"तीस",
"एकतीस",
"बत्तीस",
"तेत्तीस",
"चौंतीस",
"पैंतीस",
"छत्तीस",
"सैंतीस",
"अठतीस",
"उनन्चालीस",
"चालीस",
"एकचालीस",
"बयालीस",
"त्रिचालीस",
"चवालीस",
"पैंतालीस",
"छयालीस",
"सत्तालीस",
"अठचालीस",
"उनन्पचास",
"पचास",
"एकाउन्न",
"बाउन्न",
"त्रिपन्न",
"चउन्न",
"पचपन्न",
"छपन्न",
"सन्ताउन्न",
"अन्ठाउन्न",
"उनन्साठी",
"साठी",
"एकसाठी",
"बासट्ठी",
"त्रिसट्ठी",
"चौसट्ठी",
"पैंसट्ठी",
"छयसट्ठी",
"सतसट्ठी",
"अठसट्ठी",
"उनन्सत्तरी",
"सत्तरी",
"एकहत्तर",
"बाहत्तर",
"त्रिहत्तर",
"चौरहत्तर",
"पचहत्तर",
"छयहत्तर",
"सतहत्तर",
"अठहत्तर",
"उनन्असी",
"असी",
"एकासी",
"बयासी",
"त्रियासी",
"चौरासी",
"पचासी",
"छयासी",
"सतासी",
"अठासी",
"उनन्नब्बे",
"नब्बे",
"एकानब्बे",
"बयानब्बे",
"त्रियानब्बे",
"चौरानब्बे",
"पञ्चानब्बे",
"छ्यानब्बे",
"सन्तानब्बे",
"अन्ठानब्बे",
"उनन्सय",
]
# Nepali number units and their corresponding names
NEPALI_UNITS = [
("", ""),
(100, "सय"),
(1000, "हजार"),
(100000, "लाख"),
(10000000, "करोड"),
(1000000000, "अरब"),
(100000000000, "खरब"),
]
# Placeholder text for location selects
PLACEHOLDERS = {
"province": {"ne": "प्रदेश छान्नुहोस्", "en": "Select Province"},
"district": {"ne": "जिल्ला छान्नुहोस्", "en": "Select District"},
"municipality": {"ne": "नगरपालिका छान्नुहोस्", "en": "Select Municipality"},
}
# Internal parameters to exclude from fallback logic
INTERNAL_PARAMS = ["ne", "en", "html"]
+52
View File
@@ -0,0 +1,52 @@
"""
Language parameter utilities for django-nepkit.
Helper functions to resolve Nepali/English language parameters consistently.
"""
from django_nepkit.conf import nepkit_settings
def resolve_language_params(ne=None, en=None, **kwargs):
"""
Resolve language parameters with fallback to default settings.
"""
default_lang = nepkit_settings.DEFAULT_LANGUAGE
# Extract from kwargs if provided
if ne is None and "ne" in kwargs:
ne = kwargs.get("ne")
if en is None and "en" in kwargs:
en = kwargs.get("en")
# Set defaults
if ne is None:
ne = default_lang == "ne"
# Handle en parameter logic
explicit_en = en is not None
if en is None:
en = not ne
# If ne is True and en wasn't explicitly set, en should be False
if ne and not explicit_en:
en = False
return ne, en
def pop_language_params(kwargs):
"""
Pop ne/en parameters from kwargs dict and return resolved values.
"""
default_lang = nepkit_settings.DEFAULT_LANGUAGE
ne = kwargs.pop("ne", default_lang == "ne")
explicit_en = "en" in kwargs
en_value = kwargs.pop("en", not ne)
if ne and not explicit_en:
en = False
else:
en = en_value
return ne, en
+3 -1
View File
@@ -7,7 +7,6 @@ from django.utils.translation import gettext_lazy as _
from nepali.datetime import nepalidate, nepalidatetime
from nepali.locations import districts, municipalities, provinces
from django_nepkit.forms import NepaliDateFormField
from django_nepkit.utils import (
BS_DATE_FORMAT,
BS_DATETIME_FORMAT,
@@ -172,6 +171,9 @@ class NepaliDateField(BaseNepaliBSField):
parse_func = staticmethod(try_parse_nepali_date)
def formfield(self, **kwargs):
# Import here to avoid circular dependency
from django_nepkit.forms import NepaliDateFormField
kwargs.setdefault("form_class", NepaliDateFormField)
return super().formfield(**kwargs)
@@ -1,6 +1,20 @@
(function() {
'use strict';
// Placeholder text constants
const PLACEHOLDERS = {
province: { ne: 'प्रदेश छान्नुहोस्', en: 'Select Province' },
district: { ne: 'जिल्ला छान्नुहोस्', en: 'Select District' },
municipality: { ne: 'नगरपालिका छान्नुहोस्', en: 'Select Municipality' }
};
/**
* Get placeholder text for a specific location type
*/
function getPlaceholder(type, isNepali) {
return PLACEHOLDERS[type][isNepali ? 'ne' : 'en'];
}
function updateOptions(selectElement, data, placeholder) {
selectElement.innerHTML = '';
if (placeholder) {
@@ -43,7 +57,45 @@
return null;
}
/**
* Fetch data from server endpoint
*/
function fetchData(selectElement, paramName, paramValue, placeholderType, isNepali) {
if (!selectElement.dataset.url) return;
let url = selectElement.dataset.url + '?' + paramName + '=' + encodeURIComponent(paramValue);
if (isNepali) url += '&ne=true';
if (selectElement.dataset.en === 'true') url += '&en=true';
fetch(url)
.then(response => response.json())
.then(data => {
updateOptions(selectElement, data, getPlaceholder(placeholderType, isNepali));
});
}
/**
* Update dependent select element based on parent value
*/
function updateDependentSelect(childSelect, dataType, parentValue, placeholderType, isNepali, paramName) {
if (!childSelect) return;
if (!parentValue) {
updateOptions(childSelect, [], getPlaceholder(placeholderType, isNepali));
return;
}
const localData = getLocalData(dataType, parentValue, isNepali);
if (localData) {
updateOptions(childSelect, localData, getPlaceholder(placeholderType, isNepali));
} else {
fetchData(childSelect, paramName, parentValue, placeholderType, isNepali);
}
}
function init() {
// Initialize province selects
document.querySelectorAll('.nepkit-province-select').forEach(provinceSelect => {
const isNepali = provinceSelect.dataset.ne === 'true';
const container = provinceSelect.closest('form') || document;
@@ -52,14 +104,15 @@
if (!provinceSelect.value) {
if (districtSelect && !districtSelect.value) {
updateOptions(districtSelect, [], isNepali ? 'जिल्ला छान्नुहोस्' : 'Select District');
updateOptions(districtSelect, [], getPlaceholder('district', isNepali));
}
if (municipalitySelect && !municipalitySelect.value) {
updateOptions(municipalitySelect, [], isNepali ? 'नगरपालिका छान्नुहोस्' : 'Select Municipality');
updateOptions(municipalitySelect, [], getPlaceholder('municipality', isNepali));
}
}
});
// Initialize district selects
document.querySelectorAll('.nepkit-district-select').forEach(districtSelect => {
const isNepali = districtSelect.dataset.ne === 'true';
const container = districtSelect.closest('form') || document;
@@ -67,13 +120,14 @@
if (!districtSelect.value) {
if (municipalitySelect && !municipalitySelect.value) {
updateOptions(municipalitySelect, [], isNepali ? 'नगरपालिका छान्नुहोस्' : 'Select Municipality');
updateOptions(municipalitySelect, [], getPlaceholder('municipality', isNepali));
}
}
});
}
document.addEventListener('change', function(e) {
// Handle province select change
if (e.target.matches('.nepkit-province-select')) {
const province = e.target.value;
const isNepali = e.target.dataset.ne === 'true';
@@ -83,63 +137,22 @@
// Always clear municipality if province changes
if (municipalitySelect) {
updateOptions(municipalitySelect, [], isNepali ? 'नगरपालिका छान्नुहोस्' : 'Select Municipality');
updateOptions(municipalitySelect, [], getPlaceholder('municipality', isNepali));
}
if (districtSelect) {
if (!province) {
updateOptions(districtSelect, [], isNepali ? 'जिल्ला छान्नुहोस्' : 'Select District');
return;
}
const localData = getLocalData('districts', province, isNepali);
if (localData) {
updateOptions(districtSelect, localData, isNepali ? 'जिल्ला छान्नुहोस्' : 'Select District');
} else if (districtSelect.dataset.url) {
// Fallback to AJAX
let url = districtSelect.dataset.url + '?province=' + encodeURIComponent(province);
if (isNepali) url += '&ne=true';
if (districtSelect.dataset.en === 'true') url += '&en=true';
fetch(url)
.then(response => response.json())
.then(data => {
updateOptions(districtSelect, data, isNepali ? 'जिल्ला छान्नुहोस्' : 'Select District');
});
}
}
// Update district options
updateDependentSelect(districtSelect, 'districts', province, 'district', isNepali, 'province');
}
// Handle district select change
if (e.target.matches('.nepkit-district-select')) {
const district = e.target.value;
const isNepali = e.target.dataset.ne === 'true';
const container = e.target.closest('form') || document;
const municipalitySelect = getMatchingSelect(container, '.nepkit-municipality-select', isNepali);
if (municipalitySelect) {
if (!district) {
updateOptions(municipalitySelect, [], isNepali ? 'नगरपालिका छान्नुहोस्' : 'Select Municipality');
return;
}
const localData = getLocalData('municipalities', district, isNepali);
if (localData) {
updateOptions(municipalitySelect, localData, isNepali ? 'नगरपालिका छान्नुहोस्' : 'Select Municipality');
} else if (municipalitySelect.dataset.url) {
// Fallback to AJAX
let url = municipalitySelect.dataset.url + '?district=' + encodeURIComponent(district);
if (isNepali) url += '&ne=true';
if (municipalitySelect.dataset.en === 'true') url += '&en=true';
fetch(url)
.then(response => response.json())
.then(data => {
updateOptions(municipalitySelect, data, isNepali ? 'नगरपालिका छान्नुहोस्' : 'Select Municipality');
});
}
}
// Update municipality options
updateDependentSelect(municipalitySelect, 'municipalities', district, 'municipality', isNepali, 'district');
}
});
+74 -175
View File
@@ -122,14 +122,11 @@ def number_to_nepali_words(number: Any) -> str:
Converts a number to Nepali words.
Eg. 123 -> एक सय तेईस
"""
from django_nepkit.constants import NEPALI_ONES, NEPALI_UNITS
if number is None:
return ""
# Basic implementation for now, can be expanded
# Mapping for numbers to words (simplified)
# This is a complex task for a full implementation,
# but I'll provide a robust enough version for common usage.
try:
num = int(float(number))
except (ValueError, TypeError):
@@ -138,132 +135,19 @@ def number_to_nepali_words(number: Any) -> str:
if num == 0:
return "शून्य"
ones = [
"",
"एक",
"दुई",
"तीन",
"चार",
"पाँच",
"छ",
"सात",
"आठ",
"नौ",
"दश",
"एघार",
"बाह्र",
"तेह्र",
"चौध",
"पन्ध्र",
"सोह्र",
"सत्र",
"अठार",
"उन्नाइस",
"बीस",
"एकाइस",
"बाइस",
"तेईस",
"चौबीस",
"पच्चीस",
"छब्बीस",
"सत्ताइस",
"अठाइस",
"उनन्तीस",
"तीस",
"एकतीस",
"बत्तीस",
"तेत्तीस",
"चौंतीस",
"पैंतीस",
"छत्तीस",
"सैंतीस",
"अठतीस",
"उनन्चालीस",
"चालीस",
"एकचालीस",
"बयालीस",
"त्रिचालीस",
"चवालीस",
"पैंतालीस",
"छयालीस",
"सत्तालीस",
"अठचालीस",
"उनन्पचास",
"पचास",
"एकाउन्न",
"बाउन्न",
"त्रिपन्न",
"चउन्न",
"पचपन्न",
"छपन्न",
"सन्ताउन्न",
"अन्ठाउन्न",
"उनन्साठी",
"साठी",
"एकसाठी",
"बासट्ठी",
"त्रिसट्ठी",
"चौसट्ठी",
"पैंसट्ठी",
"छयसट्ठी",
"सतसट्ठी",
"अठसट्ठी",
"उनन्सत्तरी",
"सत्तरी",
"एकहत्तर",
"बाहत्तर",
"त्रिहत्तर",
"चौरहत्तर",
"पचहत्तर",
"छयहत्तर",
"सतहत्तर",
"अठहत्तर",
"उनन्असी",
"असी",
"एकासी",
"बयासी",
"त्रियासी",
"चौरासी",
"पचासी",
"छयासी",
"सतासी",
"अठासी",
"उनन्नब्बे",
"नब्बे",
"एकानब्बे",
"बयानब्बे",
"त्रियानब्बे",
"चौरानब्बे",
"पञ्चानब्बे",
"छ्यानब्बे",
"सन्तानब्बे",
"अन्ठानब्बे",
"उनन्सय",
]
units = [
("", ""),
(100, "सय"),
(1000, "हजार"),
(100000, "लाख"),
(10000000, "करोड"),
(1000000000, "अरब"),
(100000000000, "खरब"),
]
def _convert(n):
if n == 0:
return ""
if n < 100:
return ones[n]
return NEPALI_ONES[n]
for i in range(len(units) - 1, 0, -1):
div, unit_name = units[i]
for i in range(len(NEPALI_UNITS) - 1, 0, -1):
div, unit_name = NEPALI_UNITS[i]
if n >= div:
prefix_val = n // div
remainder = n % div
# For 'सय' (100), we use ones[prefix_val]
# For 'सय' (100), we use NEPALI_ONES[prefix_val]
# For others, we might need recursive calls if prefix_val >= 100
prefix_words = _convert(prefix_val)
res = f"{prefix_words} {unit_name}"
@@ -288,38 +172,31 @@ def english_to_nepali_unicode(text: Any) -> str:
return english_to_nepali(text)
def normalize_address(address_string: str) -> dict[str, Optional[str]]:
def _normalize_nepali_text(text):
"""
Attempts to normalize a Nepali address string into Province, District, and Municipality.
Returns a dictionary with 'province', 'district', and 'municipality'.
Normalize Nepali text for easier matching.
Replaces Chandrabindu with Anusvara.
"""
if not address_string:
return {"province": None, "district": None, "municipality": None}
result = {"province": None, "district": None, "municipality": None}
import re
content = address_string.replace(",", " ").replace("-", " ")
def normalize_nepali(text):
if not text:
return text
# Replace Chandrabindu with Anusvara for easier matching
return text.replace("ँ", "ं").replace("ाँ", "ां")
tokens = [t.strip() for t in content.split() if t.strip()]
normalized_tokens = [normalize_nepali(t) for t in tokens]
# We try to match from most specific to least specific
found_municipality = None
found_district = None
found_province = None
def _matches_location_name(name_eng, name_nep, token, normalized_token):
"""
Check if a token matches a location name (English or Nepali).
# Helper for name matching
def matches(name_eng, name_nep, token, normalized_token):
Args:
name_eng: English name of location
name_nep: Nepali name of location
token: Original token to match
normalized_token: Normalized version of token
Returns:
True if token matches the location name
"""
token_lower = token.lower()
name_nep_norm = normalize_nepali(name_nep)
name_nep_norm = _normalize_nepali_text(name_nep)
# Exact matches
if (
@@ -342,35 +219,59 @@ def normalize_address(address_string: str) -> dict[str, Optional[str]]:
return False
# Check for municipality first
for i, token in enumerate(tokens):
nt = normalized_tokens[i]
for m in municipalities:
if matches(m.name, m.name_nepali, token, nt):
found_municipality = m
break
if found_municipality:
break
# Check for district
for i, token in enumerate(tokens):
nt = normalized_tokens[i]
for d in districts:
if matches(d.name, d.name_nepali, token, nt):
found_district = d
break
if found_district:
break
def _find_location_in_tokens(location_list, tokens, normalized_tokens):
"""
Find a location from a list by matching against tokens.
# Check for province
Args:
location_list: List of location objects to search
tokens: List of original tokens
normalized_tokens: List of normalized tokens
Returns:
Matching location object or None
"""
for i, token in enumerate(tokens):
nt = normalized_tokens[i]
for p in provinces:
if matches(p.name, p.name_nepali, token, nt):
found_province = p
break
if found_province:
break
for location in location_list:
if _matches_location_name(location.name, location.name_nepali, token, nt):
return location
return None
def _is_nepali_text(tokens):
"""Check if any token contains Devanagari characters."""
import re
return any(re.search(r"[\u0900-\u097F]", t) for t in tokens)
def normalize_address(address_string: str) -> dict[str, Optional[str]]:
"""
Attempts to normalize a Nepali address string into Province, District, and Municipality.
Returns a dictionary with 'province', 'district', and 'municipality'.
"""
if not address_string:
return {"province": None, "district": None, "municipality": None}
result: dict[str, Optional[str]] = {
"province": None,
"district": None,
"municipality": None,
}
# Prepare tokens
content = address_string.replace(",", " ").replace("-", " ")
tokens = [t.strip() for t in content.split() if t.strip()]
normalized_tokens = [_normalize_nepali_text(t) for t in tokens]
# Find locations - most specific to least specific
found_municipality = _find_location_in_tokens(
municipalities, tokens, normalized_tokens
)
found_district = _find_location_in_tokens(districts, tokens, normalized_tokens)
found_province = _find_location_in_tokens(provinces, tokens, normalized_tokens)
# Fill in the gaps using hierarchy
if found_municipality:
@@ -385,13 +286,11 @@ def normalize_address(address_string: str) -> dict[str, Optional[str]]:
if not found_province:
found_province = found_district.province
if found_province:
result["province"] = found_province.name
# Check for Nepali context
is_nepali = any(
re.search(r"[\u0900-\u097F]", t) for t in tokens
) # Basic check for Devanagari characters
if is_nepali:
# Use Nepali names if input contains Nepali text
if _is_nepali_text(tokens):
if found_municipality:
result["municipality"] = found_municipality.name_nepali
if found_district:
+114 -60
View File
@@ -5,7 +5,6 @@ from django_nepkit.utils import (
get_municipalities_by_district,
)
from django_nepkit.conf import nepkit_settings
@@ -14,72 +13,127 @@ def _render_options(data, placeholder):
options = [f'<option value="">{placeholder}</option>']
for item in data:
options.append(f'<option value="{item["id"]}">{item["text"]}</option>')
return HttpResponse("\n".join(options))
return HttpResponse("\n".join(options), content_type="text/html")
def _get_primary_param(request, param_name, exclude_params=None):
"""
Extract a parameter from request.GET with fallback logic.
Args:
request: Django request object
param_name: Primary parameter name to look for
exclude_params: List of parameter names to exclude from fallback
Returns:
Parameter value or None
"""
from django_nepkit.constants import INTERNAL_PARAMS
if exclude_params is None:
exclude_params = INTERNAL_PARAMS
# Try primary parameter first
value = request.GET.get(param_name)
# Fallback: take the first non-internal parameter
if not value:
for key, val in request.GET.items():
if key not in exclude_params and val:
value = val
break
return value
def _parse_language_params(request):
"""
Parse language parameters from request.
Args:
request: Django request object
Returns:
Tuple of (ne, en) boolean values
"""
default_lang = nepkit_settings.DEFAULT_LANGUAGE
ne_param = request.GET.get("ne")
ne = ne_param.lower() == "true" if ne_param else default_lang == "ne"
en_param = request.GET.get("en")
en = en_param.lower() == "true" if en_param else not ne
return ne, en
def _should_return_html(request):
"""
Check if response should be HTML format.
Args:
request: Django request object
Returns:
Boolean indicating if HTML format is requested
"""
return (
request.GET.get("html", "false").lower() == "true"
or request.headers.get("HX-Request") == "true"
)
def _location_list_view(request, param_name, data_func, placeholders):
"""
Generic view handler for location hierarchy endpoints.
Args:
request: Django request object
param_name: Name of the primary parameter to extract
data_func: Function to call to get location data
placeholders: Tuple of (nepali_placeholder, english_placeholder)
Returns:
JsonResponse or HttpResponse with location data
"""
param_value = _get_primary_param(request, param_name)
if not param_value:
return JsonResponse([], safe=False)
ne, en = _parse_language_params(request)
as_html = _should_return_html(request)
data = data_func(param_value, ne=ne, en=en)
if as_html:
placeholder = placeholders[0] if ne else placeholders[1]
return _render_options(data, placeholder)
return JsonResponse(data, safe=False)
def district_list_view(request):
province = request.GET.get("province")
"""Return list of districts for a given province."""
from django_nepkit.constants import PLACEHOLDERS
# Fallback: take the first non-internal parameter as province
if not province:
for key, value in request.GET.items():
if key not in ["ne", "en", "html"] and value:
province = value
break
if not province:
return JsonResponse([], safe=False)
default_lang = nepkit_settings.DEFAULT_LANGUAGE
ne_param = request.GET.get("ne")
ne = ne_param.lower() == "true" if ne_param else default_lang == "ne"
en_param = request.GET.get("en")
en = en_param.lower() == "true" if en_param else not ne
as_html = (
request.GET.get("html", "false").lower() == "true"
or request.headers.get("HX-Request") == "true"
return _location_list_view(
request,
param_name="province",
data_func=get_districts_by_province,
placeholders=(PLACEHOLDERS["district"]["ne"], PLACEHOLDERS["district"]["en"]),
)
data = get_districts_by_province(province, ne=ne, en=en)
if as_html:
placeholder = "जिल्ला छान्नुहोस्" if ne else "Select District"
return _render_options(data, placeholder)
return JsonResponse(data, safe=False)
def municipality_list_view(request):
district = request.GET.get("district")
"""Return list of municipalities for a given district."""
from django_nepkit.constants import PLACEHOLDERS
# Fallback: take the first non-internal parameter as district
if not district:
for key, value in request.GET.items():
if key not in ["ne", "en", "html"] and value:
district = value
break
if not district:
return JsonResponse([], safe=False)
default_lang = nepkit_settings.DEFAULT_LANGUAGE
ne_param = request.GET.get("ne")
ne = ne_param.lower() == "true" if ne_param else default_lang == "ne"
en_param = request.GET.get("en")
en = en_param.lower() == "true" if en_param else not ne
as_html = (
request.GET.get("html", "false").lower() == "true"
or request.headers.get("HX-Request") == "true"
return _location_list_view(
request,
param_name="district",
data_func=get_municipalities_by_district,
placeholders=(
PLACEHOLDERS["municipality"]["ne"],
PLACEHOLDERS["municipality"]["en"],
),
)
data = get_municipalities_by_district(district, ne=ne, en=en)
if as_html:
placeholder = "नगरपालिका छान्नुहोस्" if ne else "Select Municipality"
return _render_options(data, placeholder)
return JsonResponse(data, safe=False)