Django subscription management with Midtrans payment gateway integration
Project description
Django Subscription Midtrans
A production-ready Django package for subscription billing with Midtrans Core API integration. Provides a complete subscription management system including recurring payments, invoicing, wallet top-ups, webhook handling, and admin dashboard.
Note: This package uses the Midtrans Core API (server-side charge via
/v2/charge,/v1/subscriptions,/v1/invoices), not Midtrans Snap.
Features
- Subscription Plans — Configurable interval billing (daily/weekly/monthly), trial periods, max billing cycles, feature flags per plan
- Payment Methods — Credit Card, Bank Transfer (BCA/BNI/BRI/Permata/CIMB), GoPay, ShopeePay, QRIS, E-Channel (Mandiri Bill), Wallet
- Automatic Billing — Celery Beat periodic tasks handle recurring charges, payment retries, grace periods, expiration
- Invoice System — Auto-generated invoices with line items, tax/discount support, PDF-ready data
- Wallet & Top-Up — Internal wallet balance system with top-up via any payment method
- Webhook Processing — Secure Midtrans notification handler with SHA-512 signature verification, duplicate detection
- Admin Dashboard — Django Unfold admin with status badges, inline editing, bulk actions, Midtrans sync
- Notification System — Email, webhook, and in-app notification logging with queued delivery
- Access Middleware — Path-based subscription enforcement with grace period support
- Django Signals — 20+ signals for all subscription/payment lifecycle events
- REST API — Full DRF ViewSet API for plans, subscriptions, payments, invoices, wallet, notifications
- Testing — Comprehensive test suite with factories, mocked Midtrans responses
Architecture
| Layer | Components |
|---|---|
| Admin UI | Django Unfold Admin |
| REST API | DRF ViewSets + Serializers |
| Service Layer | SubscriptionService, WalletService |
| Data / Integration | Models/ORM, MidtransClient, Celery Tasks (Beat) |
| External | Midtrans Core API (v2/charge, v1/subscriptions) |
For detailed Mermaid diagrams, see the Architecture Diagrams documentation.
Quick Start
Installation
From PyPI:
pip install django-subscription-midtrans
From source:
git clone https://github.com/rissets/django-subscription-midtrans.git
cd django-subscription-midtrans
pip install -e ".[dev]"
Step 1: Add to INSTALLED_APPS
INSTALLED_APPS = [
# Django Unfold (must be before django.contrib.admin)
"unfold",
"unfold.contrib.filters",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
# Third-party
"rest_framework",
"django_celery_beat",
# Subscription package
"subscriptions",
]
Step 2: Configure Environment Variables
Create a .env file in your project root:
# Django
DJANGO_SECRET_KEY=
DJANGO_DEBUG=True
DJANGO_ALLOWED_HOSTS=*,localhost,127.0.0.1
# Database (default: SQLite, configure for PostgreSQL in production)
# DB_ENGINE=django.db.backends.postgresql
# DB_NAME=subscription_db
# DB_USER=
# DB_PASSWORD=
# DB_HOST=localhost
# DB_PORT=5432
# Celery / Redis
CELERY_BROKER_URL=redis://localhost:6379/0
CELERY_RESULT_BACKEND=redis://localhost:6379/0
# Midtrans Credentials (get from https://dashboard.midtrans.com)
MIDTRANS_SERVER_KEY=
MIDTRANS_CLIENT_KEY=
MIDTRANS_MERCHANT_ID=
MIDTRANS_IS_PRODUCTION=False
# Webhook URL (must be publicly accessible)
# For local dev, use ngrok: ngrok http 8000
MIDTRANS_NOTIFICATION_URL=
Step 3: Add Settings
# settings.py
from decouple import config
# Midtrans
MIDTRANS_SERVER_KEY = config("MIDTRANS_SERVER_KEY", default="")
MIDTRANS_CLIENT_KEY = config("MIDTRANS_CLIENT_KEY", default="")
MIDTRANS_MERCHANT_ID = config("MIDTRANS_MERCHANT_ID", default="")
MIDTRANS_IS_PRODUCTION = config("MIDTRANS_IS_PRODUCTION", default=False, cast=bool)
MIDTRANS_API_BASE_URL = (
"https://api.midtrans.com" if MIDTRANS_IS_PRODUCTION
else "https://api.sandbox.midtrans.com"
)
MIDTRANS_NOTIFICATION_URL = config("MIDTRANS_NOTIFICATION_URL", default="")
# Celery
CELERY_BROKER_URL = config("CELERY_BROKER_URL", default="redis://localhost:6379/0")
CELERY_RESULT_BACKEND = config("CELERY_RESULT_BACKEND", default="redis://localhost:6379/0")
CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler"
# REST Framework
REST_FRAMEWORK = {
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 20,
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAuthenticated",
],
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework.authentication.SessionAuthentication",
"rest_framework.authentication.BasicAuthentication",
],
}
# Subscription Settings (all optional, these are defaults)
SUBSCRIPTION_SETTINGS = {
"PROTECTED_PATHS": [],
"SUBSCRIPTION_REQUIRED_REDIRECT": "/pricing/",
"GRACE_PERIOD_DAYS": 3,
"PAYMENT_EXPIRY_MINUTES": 60,
"AUTO_GENERATE_INVOICE": True,
"AUTO_RETRY_FAILED_PAYMENTS": True,
"MAX_RETRY_ATTEMPTS": 3,
"RETRY_INTERVAL_DAYS": 1,
"INVOICE_NUMBER_PREFIX": "INV",
"SEND_EMAIL_NOTIFICATIONS": True,
"EXPIRY_REMINDER_DAYS": [7, 3, 1],
}
Step 4: Include URLs
# urls.py
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path("api/subscriptions/", include("subscriptions.urls")),
]
Step 5: Run Migrations and Setup
# Apply database migrations
python manage.py migrate
# Create periodic Celery tasks
python manage.py setup_periodic_tasks
# Seed sample subscription plans (optional, for development)
python manage.py seed_plans
# Create admin superuser
python manage.py createsuperuser
Step 6: Start Services
You need 4 processes running:
# Terminal 1: Redis (message broker)
redis-server
# Terminal 2: Django development server
python manage.py runserver
# Terminal 3: Celery worker (processes async tasks)
celery -A config worker -l info
# Terminal 4: Celery beat (schedules periodic tasks)
celery -A config beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
Development Setup
Prerequisites
- Python 3.10+
- Redis server
- Git
Clone & Install
git clone https://github.com/rissets/django-subscription-midtrans.git
cd django-subscription-midtrans
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # macOS/Linux
# .venv\Scripts\activate # Windows
# Install dependencies
pip install -r requirements.txt
# Copy environment file
cp .env.example .env
# Edit .env with your Midtrans sandbox credentials
Midtrans Sandbox Setup
- Register at https://dashboard.sandbox.midtrans.com
- Get your Server Key and Client Key from Settings → Access Keys
- Add them to your
.envfile - For webhooks, expose your local server:
# Install ngrok: https://ngrok.com ngrok http 8000 # Copy the HTTPS URL and set MIDTRANS_NOTIFICATION_URL in .env
Run the Example App
The project includes a full example application demonstrating all features:
# Apply migrations
python manage.py migrate
# Seed plans and periodic tasks
python manage.py seed_plans --reset
python manage.py setup_periodic_tasks --reset
# Create a superuser for admin access
python manage.py createsuperuser
# Start all services (in separate terminals)
redis-server
python manage.py runserver
celery -A config worker -l info
celery -A config beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
Then visit:
- Example App: http://localhost:8000/example/
- Admin Dashboard: http://localhost:8000/admin/
- API Root: http://localhost:8000/api/subscriptions/
Test Credentials (Sandbox)
| Payment Method | Test Details |
|---|---|
| Credit Card | Card: 4811 1111 1111 1114, Exp: 01/29, CVV: 123, OTP: 112233 |
| BCA VA | Use the VA number from the response, simulate payment in Midtrans dashboard |
| BNI VA | Use the VA number from the response |
| GoPay | Use the QR code or deeplink from the response |
| QRIS | Scan the QR code with any QRIS-compatible app (sandbox mode) |
Running Tests
# Run all subscription tests
python manage.py test subscriptions
# Run specific test module
python manage.py test subscriptions.tests.test_models
python manage.py test subscriptions.tests.test_services
python manage.py test subscriptions.tests.test_views
python manage.py test subscriptions.tests.test_client
python manage.py test subscriptions.tests.test_middleware
# Run with verbosity
python manage.py test subscriptions -v 2
Documentation
Full Sphinx documentation is available in the docs/ directory:
cd docs
pip install -r requirements.txt
make html
# Open docs/_build/html/index.html
API Reference
Plans
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/subscriptions/plans/ |
No | List all active plans |
GET |
/api/subscriptions/plans/{slug}/ |
No | Get plan details by slug |
Subscriptions
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/subscriptions/subscriptions/ |
Yes | List user's subscriptions |
POST |
/api/subscriptions/subscriptions/ |
Yes | Create subscription |
GET |
/api/subscriptions/subscriptions/{id}/ |
Yes | Get subscription detail |
GET |
/api/subscriptions/subscriptions/active/ |
Yes | Get active subscription |
POST |
/api/subscriptions/subscriptions/{id}/cancel/ |
Yes | Cancel subscription |
POST |
/api/subscriptions/subscriptions/{id}/pause/ |
Yes | Pause subscription |
POST |
/api/subscriptions/subscriptions/{id}/resume/ |
Yes | Resume subscription |
POST |
/api/subscriptions/subscriptions/{id}/change-plan/ |
Yes | Change subscription plan |
GET |
/api/subscriptions/subscriptions/{id}/sync/ |
Yes | Sync with Midtrans |
Payments
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/subscriptions/payments/ |
Yes | List user's payments |
GET |
/api/subscriptions/payments/{id}/ |
Yes | Get payment detail |
POST |
/api/subscriptions/payments/charge/ |
Yes | Create charge for subscription |
POST |
/api/subscriptions/payments/{id}/refund/ |
Yes | Refund a payment |
GET |
/api/subscriptions/payments/{id}/check-status/ |
Yes | Check Midtrans status |
Invoices
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/subscriptions/invoices/ |
Yes | List user's invoices |
GET |
/api/subscriptions/invoices/{id}/ |
Yes | Get invoice detail |
Wallet
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/subscriptions/wallet/me/ |
Yes | Get user's wallet |
GET |
/api/subscriptions/wallet/transactions/ |
Yes | List wallet transactions |
Top-Ups
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/subscriptions/topups/ |
Yes | List user's top-ups |
POST |
/api/subscriptions/topups/ |
Yes | Create a top-up |
GET |
/api/subscriptions/topups/{id}/ |
Yes | Get top-up detail |
Notifications
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/subscriptions/notifications/ |
Yes | List notifications |
GET |
/api/subscriptions/notifications/unread/ |
Yes | Get unread notifications |
POST |
/api/subscriptions/notifications/{id}/mark-read/ |
Yes | Mark notification as read |
Webhook
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/api/subscriptions/webhook/notification/ |
No | Midtrans webhook handler |
API Usage Examples
Create Subscription (Bank Transfer - BCA)
curl -X POST http://localhost:8000/api/subscriptions/subscriptions/ \
-H "Content-Type: application/json" \
-b "sessionid=<your-session-id>" \
-d '{
"plan_id": "<plan-uuid>",
"payment_type": "bank_transfer",
"customer_details": {
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "081234567890"
}
}'
Response:
{
"id": "uuid",
"plan": { "name": "Pro Monthly", "price": "299000.00" },
"status": "pending",
"payment_type": "bank_transfer",
"payments": [{
"order_id": "SUB-xxxxx",
"status": "pending",
"payment_details": {
"bank": "bca",
"va_number": "9898123456789"
}
}]
}
Create Subscription (GoPay)
curl -X POST http://localhost:8000/api/subscriptions/subscriptions/ \
-H "Content-Type: application/json" \
-b "sessionid=<your-session-id>" \
-d '{
"plan_id": "<plan-uuid>",
"payment_type": "gopay"
}'
Response includes deeplink/QR for GoPay payment.
Create Subscription (QRIS)
curl -X POST http://localhost:8000/api/subscriptions/subscriptions/ \
-H "Content-Type: application/json" \
-b "sessionid=<your-session-id>" \
-d '{
"plan_id": "<plan-uuid>",
"payment_type": "qris"
}'
Response includes QR code URL for scanning.
Create Subscription (Credit Card)
curl -X POST http://localhost:8000/api/subscriptions/subscriptions/ \
-H "Content-Type: application/json" \
-b "sessionid=<your-session-id>" \
-d '{
"plan_id": "<plan-uuid>",
"payment_type": "credit_card",
"token": "<card-token-from-midtrans-js>"
}'
Create Subscription (Wallet)
curl -X POST http://localhost:8000/api/subscriptions/subscriptions/ \
-H "Content-Type: application/json" \
-b "sessionid=<your-session-id>" \
-d '{
"plan_id": "<plan-uuid>",
"payment_type": "wallet"
}'
Cancel Subscription
curl -X POST http://localhost:8000/api/subscriptions/subscriptions/<uuid>/cancel/ \
-H "Content-Type: application/json" \
-b "sessionid=<your-session-id>" \
-d '{"reason": "Switching provider", "immediate": false}'
Top Up Wallet
curl -X POST http://localhost:8000/api/subscriptions/topups/ \
-H "Content-Type: application/json" \
-b "sessionid=<your-session-id>" \
-d '{
"amount": 500000,
"payment_type": "bank_transfer",
"bank": "bca"
}'
Refund Payment
curl -X POST http://localhost:8000/api/subscriptions/payments/<uuid>/refund/ \
-H "Content-Type: application/json" \
-b "sessionid=<your-session-id>" \
-d '{"amount": 150000, "reason": "Partial refund"}'
Configuration Reference
All settings are configured via SUBSCRIPTION_SETTINGS dict in your Django settings:
SUBSCRIPTION_SETTINGS = {
# Access Control
"PROTECTED_PATHS": ["/api/premium/", "/pro-features/"],
"SUBSCRIPTION_REQUIRED_REDIRECT": "/pricing/",
# Grace Period
"GRACE_PERIOD_DAYS": 3, # Days after failed payment to keep access
# Payment
"PAYMENT_EXPIRY_MINUTES": 60, # Payment token/VA expiry time
# Invoicing
"AUTO_GENERATE_INVOICE": True, # Auto-create invoice on charge
"INVOICE_NUMBER_PREFIX": "INV", # Invoice number format: INV-2026-0001
# Retry Logic
"AUTO_RETRY_FAILED_PAYMENTS": True,
"MAX_RETRY_ATTEMPTS": 3,
"RETRY_INTERVAL_DAYS": 1,
# Notifications
"SEND_EMAIL_NOTIFICATIONS": True,
"EXPIRY_REMINDER_DAYS": [7, 3, 1], # Days before expiry to send reminders
}
Subscription Lifecycle
Subscription states and transitions:
| From | Event | To |
|---|---|---|
| — | create_subscription() |
PENDING |
| PENDING | Payment success | ACTIVE |
| PENDING | Plan has trial days | TRIALING |
| PENDING | Payment expired/failed | EXPIRED |
| TRIALING | Trial ends + payment success | ACTIVE |
| TRIALING | Trial ends + payment failed | EXPIRED |
| ACTIVE | Renewal payment failed | PAST_DUE |
| ACTIVE | User pauses | PAUSED |
| ACTIVE | User cancels (immediate) | CANCELLED |
| ACTIVE | Period ends + cancel_at_period_end | CANCELLED |
| PAST_DUE | Retry payment success | ACTIVE |
| PAST_DUE | Grace period expired | EXPIRED |
| PAUSED | User resumes | ACTIVE |
| PAUSED | User cancels | CANCELLED |
Two Subscription Modes
| Mode | Payment Types | How It Works |
|---|---|---|
| Native Midtrans Subscription | Credit Card, GoPay (with account_id) | Uses /v1/subscriptions API — Midtrans handles automatic recurring billing |
| Manual Charge Subscription | Bank Transfer, QRIS, ShopeePay, E-Channel, Wallet | Each billing cycle creates a new /v2/charge — managed by Celery Beat |
Celery Periodic Tasks
| Task | Schedule | Description |
|---|---|---|
process_due_subscriptions |
Every 1 hour | Charges subscriptions with next_billing_date <= now |
process_expired_subscriptions |
Every 6 hours | Cancels subscriptions marked cancel_at_period_end |
process_past_due_expiration |
Every 12 hours | Expires subscriptions past grace period |
retry_failed_payments |
Every 4 hours | Retries failed charges (up to MAX_RETRY_ATTEMPTS) |
process_wallet_billing |
Every 1 hour | Deducts wallet balance for wallet-based subscriptions |
mark_overdue_invoices |
Daily 1:00 AM | Marks unpaid invoices as overdue |
send_expiry_reminders |
Daily 9:00 AM | Sends reminders N days before subscription expiry |
sync_midtrans_subscriptions |
Every 6 hours | Syncs native Midtrans subscription statuses |
send_pending_email_notifications |
Every 5 min | Processes queued email notifications |
Webhook Setup
Configure Midtrans Dashboard
- Log in at Midtrans Dashboard (or sandbox)
- Go to Settings → Configuration
- Set Payment Notification URL:
https://yourdomain.com/api/subscriptions/webhook/notification/ - Enable notifications for all transaction statuses
Local Development with ngrok
ngrok http 8000
# Example output: https://abc123.ngrok-free.app
# Set in .env:
# MIDTRANS_NOTIFICATION_URL=https://abc123.ngrok-free.app/api/subscriptions/webhook/notification/
Signature Verification
All incoming webhooks are verified using SHA-512:
SHA512(order_id + status_code + gross_amount + server_key) == signature_key
Invalid signatures are rejected and logged. Duplicate notifications are detected and skipped.
Django Signals
Connect to subscription events in your app:
from django.dispatch import receiver
from subscriptions.signals import (
subscription_activated,
payment_success,
payment_failed,
subscription_plan_changed,
)
@receiver(subscription_activated)
def on_subscription_activated(sender, subscription, **kwargs):
# Grant access to premium features
pass
@receiver(payment_success)
def on_payment_success(sender, payment, **kwargs):
# Send receipt email
pass
@receiver(payment_failed)
def on_payment_failed(sender, payment, **kwargs):
# Notify user of failed payment
pass
@receiver(subscription_plan_changed)
def on_plan_changed(sender, subscription, old_plan, new_plan, **kwargs):
# Adjust user features
pass
Available Signals
| Signal | Arguments | Triggered When |
|---|---|---|
subscription_created |
subscription |
New subscription created |
subscription_activated |
subscription |
Subscription becomes active |
subscription_cancelled |
subscription |
Subscription cancelled |
subscription_paused |
subscription |
Subscription paused |
subscription_resumed |
subscription |
Subscription resumed |
subscription_expired |
subscription |
Subscription expired |
subscription_renewed |
subscription |
Billing cycle renewed |
subscription_plan_changed |
subscription, old_plan, new_plan |
Plan changed |
payment_created |
payment |
New payment created |
payment_success |
payment |
Payment settled |
payment_failed |
payment |
Payment failed |
payment_refunded |
payment |
Payment refunded |
invoice_created |
invoice |
Invoice generated |
invoice_paid |
invoice |
Invoice paid |
invoice_overdue |
invoice |
Invoice past due date |
invoice_voided |
invoice |
Invoice voided |
webhook_received |
webhook_log |
Midtrans webhook received |
webhook_processed |
webhook_log |
Webhook processed |
topup_completed |
topup |
Wallet top-up completed |
wallet_credited |
transaction |
Wallet balance increased |
wallet_debited |
transaction |
Wallet balance decreased |
Middleware
Protect routes based on subscription status:
# settings.py
MIDDLEWARE = [
# ... other middleware
"subscriptions.middleware.SubscriptionAccessMiddleware",
]
SUBSCRIPTION_SETTINGS = {
"PROTECTED_PATHS": ["/api/premium/", "/dashboard/pro/"],
"SUBSCRIPTION_REQUIRED_REDIRECT": "/pricing/",
}
Behavior:
- API requests without active subscription →
403 JSONresponse - HTML requests without active subscription → redirect to pricing page
- Staff users always bypass the check
- Grace period is respected (users with
PAST_DUEwithin grace period still have access)
Admin Dashboard
The package uses Django Unfold for a modern admin interface:
- Plan Management — Create/edit plans, activate/deactivate, view subscriber counts
- Subscription Management — Status badges, pause/resume/cancel actions, sync from Midtrans
- Payment Tracking — View payments with fraud status, check/cancel/expire from admin
- Invoice Management — View invoices with line items, mark paid, void
- Webhook Logs — Audit trail of all Midtrans notifications
- Wallet & Top-Up — View user wallets and transaction history
Access at: http://localhost:8000/admin/
Extending the Package
Custom Signal Handlers
# your_app/signals.py
from django.dispatch import receiver
from subscriptions.signals import subscription_activated
@receiver(subscription_activated)
def grant_premium_access(sender, subscription, **kwargs):
user = subscription.user
user.profile.is_premium = True
user.profile.save()
Override Service Methods
from subscriptions.services import SubscriptionService
class CustomSubscriptionService(SubscriptionService):
def activate_subscription(self, subscription):
result = super().activate_subscription(subscription)
send_welcome_package(subscription.user)
return result
Proxy Models
from subscriptions.models import Subscription
class PremiumSubscription(Subscription):
class Meta:
proxy = True
def has_feature(self, feature_name):
return self.plan.features.get(feature_name, False)
Production Deployment
Environment Variables
DJANGO_SECRET_KEY=<strong-random-key>
DJANGO_DEBUG=False
DJANGO_ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com
# PostgreSQL (recommended for production)
DB_ENGINE=django.db.backends.postgresql
DB_NAME=subscription_db
DB_USER=
DB_PASSWORD=
DB_HOST=localhost
DB_PORT=5432
# Redis
CELERY_BROKER_URL=redis://localhost:6379/0
CELERY_RESULT_BACKEND=redis://localhost:6379/0
# Midtrans Production
MIDTRANS_SERVER_KEY=
MIDTRANS_CLIENT_KEY=
MIDTRANS_MERCHANT_ID=
MIDTRANS_IS_PRODUCTION=True
MIDTRANS_NOTIFICATION_URL=https://yourdomain.com/api/subscriptions/webhook/notification/
Production Checklist
- Set
DEBUG=False - Use PostgreSQL (not SQLite)
- Set
MIDTRANS_IS_PRODUCTION=True - Use production Midtrans keys (not sandbox)
- Configure
MIDTRANS_NOTIFICATION_URLto your public HTTPS URL - Run
python manage.py collectstatic - Run
python manage.py migrate - Run
python manage.py setup_periodic_tasks - Use a process manager (systemd, supervisor) for Celery workers
- Configure HTTPS (required by Midtrans for production)
- Set up monitoring for Celery tasks and webhook logs
Systemd Services
Celery Worker
# /etc/systemd/system/celery-worker.service
[Unit]
Description=Celery Worker
After=network.target redis.service
[Service]
Type=simple
User=www-data
WorkingDirectory=/path/to/project
ExecStart=/path/to/venv/bin/celery -A config worker -l info
Restart=always
[Install]
WantedBy=multi-user.target
Celery Beat
# /etc/systemd/system/celery-beat.service
[Unit]
Description=Celery Beat Scheduler
After=network.target redis.service
[Service]
Type=simple
User=www-data
WorkingDirectory=/path/to/project
ExecStart=/path/to/venv/bin/celery -A config beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
Restart=always
[Install]
WantedBy=multi-user.target
Docker Compose
docker-compose.yml
version: "3.8"
services:
web:
build: .
command: gunicorn config.wsgi:application --bind 0.0.0.0:8000
volumes:
- .:/app
ports:
- "8000:8000"
env_file: .env
depends_on:
- db
- redis
db:
image: postgres:16
environment:
POSTGRES_DB: ${DB_NAME:-subscription_db}
POSTGRES_USER: ${DB_USER:-dbuser}
POSTGRES_PASSWORD: ${DB_PASSWORD:-secret}
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
celery-worker:
build: .
command: celery -A config worker -l info
env_file: .env
depends_on:
- db
- redis
celery-beat:
build: .
command: celery -A config beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
env_file: .env
depends_on:
- db
- redis
volumes:
pgdata:
Project Structure
| Directory | Description |
|---|---|
config/ |
Django project settings, Celery config, URL routing, WSGI |
subscriptions/ |
Main reusable package (models, services, views, signals, tasks, admin, middleware, client) |
subscriptions/tests/ |
Test suite with factories |
subscriptions/management/commands/ |
seed_plans, setup_periodic_tasks management commands |
example/ |
Example Django app with template-based views and template tags |
templates/example/ |
HTML templates (Tailwind CSS) |
docs/ |
Sphinx documentation |
License
This project is licensed under the MIT License — see the LICENSE file for details.
Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Commit your changes:
git commit -am 'Add my feature' - Push to the branch:
git push origin feature/my-feature - Open a Pull Request
Resources
Project details
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 django_subscription_midtrans-0.1.3.tar.gz.
File metadata
- Download URL: django_subscription_midtrans-0.1.3.tar.gz
- Upload date:
- Size: 61.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2b19f47f67afbce7e5766056b5d05a64d48412be4e359a5a9ff841e0ff5f0aa3
|
|
| MD5 |
039d8761c1c73b2555367bb706bda1af
|
|
| BLAKE2b-256 |
9a8e016cbe6ba83df61dadc996590806c2a6224a421185b3996a9dd83f75f9e8
|
File details
Details for the file django_subscription_midtrans-0.1.3-py3-none-any.whl.
File metadata
- Download URL: django_subscription_midtrans-0.1.3-py3-none-any.whl
- Upload date:
- Size: 62.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc00523ef9c09cf3640dc178808832476f777e7b9989993b576831bb6e9e2410
|
|
| MD5 |
bd1c03e60197c1f1a02b4cf74e4bdda7
|
|
| BLAKE2b-256 |
b74bb5b85a22c6c5b13d10dd7682eed08079949b0a4ebe40d359a0faf38c750f
|