Django zone-based courier shipping cost calculator — by Nitesh Kumar Singh (nkscoder)
Project description
Courier — Generic Django Zone-Based Shipping Cost Calculator
Author: Nitesh Kumar Singh · GitHub: @nkscoder
A generic, reusable Django courier app for calculating zone-based shipping costs by weight, quantity, and destination. Works out of the box with built-in country/region models, or plugs into your existing location tables. Built by Nitesh Kumar Singh (nkscoder).
Keywords: django courier · generic shipping calculator · zone-based shipping · weight pricing · reusable django app · nkscoder · nitesh kumar singh · python shipping
Features
- Generic by design — built-in
CourierCountry/CourierRegionmodels, nocoreapp required - Configurable pricing — domestic multiplier, international surcharge %, weight units, thresholds
- Zone-based pricing — map countries and regions to shipping zones
- Weight slab lookup — automatic cost lookup by weight brackets
- Multi-unit support — grams, kilograms, and pounds (
gram,kgs,lbs) - JSON API endpoint — real-time shipping quotes via HTTP GET
- Python API — call
calculate_courier_cost()from checkout, cart, or background jobs - Custom zone resolver — plug in your own location models with one settings hook
- Django Admin — manage countries, regions, zones, and weight costs
Requirements
- Python 3.8–3.12 (including 3.12)
- Django 3.2+
Installation
pip install nkscoder-courier
With Django Admin CSV import/export:
pip install "nkscoder-courier[admin]"
From GitHub:
pip install git+https://github.com/nkscoder/courier.git
Quick start
# settings.py
INSTALLED_APPS = [
...
"courier",
]
COURIER_DOMESTIC_COUNTRY_NAME = "India"
COURIER_INTERNATIONAL_SURCHARGE_PERCENT = 22
python manage.py migrate courier
# urls.py
urlpatterns = [
path("courier/", include("courier.urls")),
]
Usage
Python API (recommended)
from courier.calculator import calculate_courier_cost
total = calculate_courier_cost(
weight=1.5,
quantity=2,
weight_unit="kgs",
country_id=country.pk,
region_id=region.pk, # optional for domestic regions
)
Backward-compatible alias:
from courier import courier_cost
total = courier_cost(weight=500, quantity=1, weight_unit="gram", country=1, state=3)
HTTP API
GET /courier/?weight=500&quantity=2&weight_unit=gram&country=1®ion=3
Response:
{"total": 150}
| Parameter | Description |
|---|---|
weight |
Package weight |
quantity |
Number of packages |
weight_unit |
gram, kgs, or lbs |
country |
Country PK |
region or state |
Region PK (for domestic destinations) |
Configuration
All settings use the COURIER_ prefix:
| Setting | Default | Description |
|---|---|---|
COURIER_COUNTRY_MODEL |
courier.CourierCountry |
Country model label |
COURIER_REGION_MODEL |
courier.CourierRegion |
Region/state model label |
COURIER_DOMESTIC_COUNTRY_NAME |
India |
Fallback domestic country name |
COURIER_INTERNATIONAL_SURCHARGE_PERCENT |
22 |
Surcharge for non-domestic destinations |
COURIER_HEAVY_WEIGHT_THRESHOLD_KG |
20 |
Heavy shipment threshold |
COURIER_WEIGHT_PADDING_KG |
0.500 |
Padding added to billable weight |
COURIER_WEIGHT_INCREMENT_KG |
0.500 |
Domestic weight multiplier increment |
COURIER_DEFAULT_WEIGHT_UNIT |
gram |
Default unit for API requests |
COURIER_DOMESTIC_USE_WEIGHT_MULTIPLIER |
True |
Per-increment pricing for domestic |
COURIER_ZONE_RESOLVER |
None |
Custom (country_id, region_id) -> (connection, surcharge) |
Plug into your own location models
# settings.py
COURIER_COUNTRY_MODEL = "myapp.Country"
COURIER_REGION_MODEL = "myapp.State"
def resolve_courier_zone(country_id, region_id):
from courier.models import ZoneConnection
# your lookup logic
return connection, apply_surcharge
COURIER_ZONE_RESOLVER = resolve_courier_zone
Mark domestic countries with is_domestic=True on your model, or rely on COURIER_DOMESTIC_COUNTRY_NAME.
Admin setup
- Courier Country — add destinations; mark domestic with
is_domestic - Courier Region — add states/provinces under domestic countries
- Zone — create shipping zones (Zone A, Zone B, …)
- Zone Connection — link zones to countries and/or regions
- Weight Cost — set price per weight slab for each zone
How pricing works
- Resolve the destination zone from country/region via
ZoneConnection - Normalize weight to grams and compute total billable weight
- Look up the matching WeightCost slab for that zone
- Domestic: multiply slab rate by weight increments (configurable)
- International: apply configurable surcharge % on the base rate
Development
git clone git@github.com:nkscoder/courier.git
cd courier
pip install -e ".[admin]"
python manage.py migrate
python manage.py test courier
Changelog
1.1.1
- Renamed PyPI package to
nkscoder-courier(namecourierwas taken on PyPI) - Fixed GitHub Actions publish workflow with
PYPI_API_TOKEN
1.1.0
- Generic built-in
CourierCountry/CourierRegionmodels (nocoredependency) - New
calculate_courier_cost()service API - Configurable settings via
COURIER_*prefix - Optional custom
COURIER_ZONE_RESOLVERhook - Improved admin with search and filters
1.0.0
- Initial PyPI release by Nitesh Kumar Singh (nkscoder)
Author & Links
| Author | Nitesh Kumar Singh |
| GitHub | github.com/nkscoder |
| Repository | github.com/nkscoder/courier |
| PyPI | pypi.org/project/nkscoder-courier |
License
MIT License — Copyright (c) 2020-2026 Nitesh Kumar Singh (nkscoder)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nkscoder_courier-1.1.1.tar.gz.
File metadata
- Download URL: nkscoder_courier-1.1.1.tar.gz
- Upload date:
- Size: 13.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
355877bf732269d0d268c584b71261b8a82ce558f43eba5be0e9cfb96ca6c9a4
|
|
| MD5 |
101e822be9c88ebf784b6efbd952bf46
|
|
| BLAKE2b-256 |
37680da334a337297d1879d671a918ca2623d09bda52b367d17d24b4cdba3d81
|
File details
Details for the file nkscoder_courier-1.1.1-py3-none-any.whl.
File metadata
- Download URL: nkscoder_courier-1.1.1-py3-none-any.whl
- Upload date:
- Size: 13.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
58da4833888ab2248cbd0fd254b835f70d868825c3854f6ffe99649bafcce431
|
|
| MD5 |
46936e8d657471fc114e28af9c58b123
|
|
| BLAKE2b-256 |
0f2efedb2867bec498d5b11ee8fc4f3f746d73b0131bc25d2fe25ac341ccad90
|