Django coupon and discount code system with validation rules — by Nitesh Kumar Singh (nkscoder)
Project description
Coupons — Django Coupon & Discount Code System
Author: Nitesh Kumar Singh · GitHub: @nkscoder
A reusable Django coupons app for managing promotional codes, discount rules, and coupon validation in Python web applications. Built by Nitesh Kumar Singh (nkscoder) for e-commerce, SaaS, and any Django project that needs flexible coupon functionality.
Keywords: django coupons · python coupon system · discount code · promo code · coupon validation · nkscoder · nitesh kumar singh
Features
- Percentage or fixed-amount discounts on any order total
- User-specific or global coupons — restrict codes to selected users or allow all
- Usage limits — max total uses, uses per user, or unlimited
- Expiration & active/inactive rules with datetime-based validity
- Django Admin integration with bulk actions (reset usage, delete expired)
- Simple validation API — one function call to check any coupon code
- Configurable coupon code length via
DSC_COUPON_CODE_LENGTHsetting
Requirements
- Python 3.8+
- Django 3.2+
Installation
From PyPI (recommended)
pip install coupons
From GitHub
pip install git+https://github.com/nkscoder/coupons.git
Setup
Step 1 — Add to INSTALLED_APPS
# settings.py
INSTALLED_APPS = [
...
"coupons",
]
Step 2 — Run migrations
python manage.py migrate coupons
Step 3 — Create coupons in Django Admin
Go to /admin/ and create:
- Discount — set value and type (percentage or fixed)
- Allowed Users Rule — select users or enable "All users"
- Max Uses Rule — set limits or enable infinite uses
- Validity Rule — set expiration date and active status
- Ruleset — link the three rules above
- Coupon — assign discount and ruleset (code auto-generated)
Step 4 (optional) — Custom coupon code length
# settings.py
DSC_COUPON_CODE_LENGTH = 16 # default is 12
Usage
Validate a coupon
from coupons.validations import validate_coupon
coupon_code = "COUPONTEST01"
user = User.objects.get(username="nitesh")
status = validate_coupon(coupon_code=coupon_code, user=user)
# {'valid': True}
if status["valid"]:
print("Coupon is valid!")
else:
print(status["message"]) # e.g. "Coupon does not exist!"
Apply a coupon (record usage)
from coupons.models import Coupon
coupon = Coupon.objects.get(code=coupon_code)
coupon.use_coupon(user=user)
Get discount details
coupon = Coupon.objects.get(code=coupon_code)
discount = coupon.get_discount()
# {'value': 50, 'is_percentage': True}
Calculate discounted price
discounted = coupon.get_discounted_value(initial_value=100.0)
# Returns 50.0 for 50% off, or 80.0 for $20 off
Validation Rules
| Rule | Description |
|---|---|
| Allowed Users | Coupon valid only for selected users, or all users |
| Max Uses | Global usage cap, per-user limit, or infinite |
| Validity | Active flag + expiration datetime |
Invalid responses include a human-readable message key:
validate_coupon("DUMMYCODE", user)
# {'valid': False, 'message': 'Coupon does not exist!'}
REST API Example
See examples/ for a Django REST Framework integration sample (ajax_views.py, ajax_urls.py).
Development
git clone git@github.com:nkscoder/coupons.git
cd coupons
pip install -e ".[dev]"
python manage.py migrate
python manage.py runserver
Build & publish to PyPI
pip install build twine
python -m build
twine upload dist/*
Or tag a release on GitHub — the included GitHub Action publishes automatically.
Changelog
1.1.0
- Modernized for Django 3.2–5.x and Python 3.8+
- Added PyPI packaging (
pyproject.toml) - Fixed per-coupon usage validation bug
- Fixed template mutation in validation responses
- SEO & documentation update by Nitesh Kumar Singh (nkscoder)
1.0.0
- Initial release
Author & Links
| Author | Nitesh Kumar Singh |
| GitHub | github.com/nkscoder |
| Repository | github.com/nkscoder/coupons |
| PyPI | pypi.org/project/coupons |
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 coupons-1.1.1.tar.gz.
File metadata
- Download URL: coupons-1.1.1.tar.gz
- Upload date:
- Size: 11.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 |
31825e8fa3908eab407d7b7972a10bada99e3199f86a0c708aef0d7911436410
|
|
| MD5 |
f08b49ab5980c9c1cb51c2007e479bc0
|
|
| BLAKE2b-256 |
ff6257d39fda3f2d15b0e080863d6b15fc188003576c2b1bfd33a2cb6af24967
|
File details
Details for the file coupons-1.1.1-py3-none-any.whl.
File metadata
- Download URL: coupons-1.1.1-py3-none-any.whl
- Upload date:
- Size: 10.6 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 |
4390cc8c819e8b94273870fa1734ca3004a8d0ee1207a00dc44294ed84bc6656
|
|
| MD5 |
a10be638a85ba68e1c4ce72cc151e938
|
|
| BLAKE2b-256 |
575efc106b3836ab5b98f366d742a87a7208c2bde3a082d0184fa415268723af
|