A Django REST API project template with JWT authentication, user management, and Docker support.
- Django 5.x.x with Django REST Framework
- JWT Authentication using SimpleJWT
- PostgreSQL database support (with SQLite fallback)
- API documentation with drf-yasg (Swagger/OpenAPI)
- CORS headers configuration
- Docker support
- User management system
- Custom permissions and serializers
- Python 3.10+
- PostgreSQL (optional, SQLite is used by default)
- pip (Python package manager)
- Virtual environment (recommended)
The fastest way to get started:
# Make the script executable
chmod +x entrypoint.sh
# Run the setup script
./entrypoint.shThis script will:
- Create a virtual environment
- Activate it
- Copy
.env.sampleto.env(if available) - Install all dependencies
- Run migrations
- Clone the repository
git clone <repository-url>- Create and activate a virtual environment
python3 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate- Install dependencies
pip install -r requirements.txt- Set up environment variables
Create a .env file in the project root with the following variables:
# Debug mode (True for development, False for production)
DEBUG=True
# Django secret key (generate a secure key for production)
SECRET_KEY=your-secret-key-here
# Database URL (optional, defaults to SQLite)
# For PostgreSQL: postgresql://user:password@localhost:5432/dbname
DATABASE_URL=sqlite:///db.sqlite3
# CORS settings (comma-separated URLs)
CORS_ALLOWED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
# Email configuration (optional)
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_HOST_USER=your-email@gmail.com
EMAIL_HOST_PASSWORD=your-app-password
# Project configuration (optional)
PROJECT_NAME=Django Project
PROJECT_DESCRIPTION=Django REST API Project
PROJECT_VERSION=v1
SWAGGER_DEFAULT_API_URL=http://127.0.0.1:8000
# Production settings (optional)
PROD_ENV_DISABLE_SWAGGER=False
PROD_ENV_DISABLE_ADMIN=False- Run database migrations
python manage.py makemigrations
python manage.py migrate- Create a superuser (optional)
python manage.py createsuperuser- Run the development server
python manage.py runserverThe API will be available at http://127.0.0.1:8000/
- Build the Docker image
docker build -t django-template .- Run the container
docker run -p 8000:8000 -v $(pwd):/app django-templatedocker-compose upThis project uses Django's built-in test runner (works with any app in this codebase — swap
<app_name> / <app_name>.tests.<ClassName> / ...::test_method_name for the app or test you want).
Make sure migrations exist for every app before running tests, otherwise Django's test database won't have the required tables:
python manage.py makemigrationsRun the entire test suite (all apps):
python manage.py testRun tests for a single app:
python manage.py test <app_name>Run a single test class:
python manage.py test <app_name>.tests.<TestClassName>Run a single test method:
python manage.py test <app_name>.tests.<TestClassName>.<test_method_name>Control how much detail is printed while tests run:
python manage.py test <app_name> -v 0 # Silent — only final OK/FAILED
python manage.py test <app_name> -v 1 # Default — dot progress (. per passing test)
python manage.py test <app_name> -v 2 # Verbose — prints each test's name and result
python manage.py test <app_name> -v 3 # Very verbose — includes DB setup/teardown logsUse -v 2 when writing new tests or debugging a failure — it shows exactly which test
ran and whether it passed.
By default, Django creates a fresh test database, applies all migrations, runs the tests, then destroys the database — every single run. On larger projects this migration step can be slow.
Use --keepdb to reuse the test database between runs (only new migrations get applied):
python manage.py test <app_name> --keepdbIf you change model fields significantly, run once without
--keepdbto avoid schema drift between the kept test database and your current models.
python manage.py test --parallelpython manage.py test <app_name> -v 2 --keepdbpytest <app_name>/tests.py -v
pytest <app_name>/tests.py::<TestClassName>::<test_method_name> -v
pytest --reuse-db # equivalent of --keepdbWhen a test touches an external API (payment gateway, AI/LLM calls, email sending, PDF/file generation libraries, etc.), mock it instead of calling the real service — tests should be fast, deterministic, and runnable offline/in CI without real credentials:
from unittest.mock import patch
@patch('<app_name>.<module>.<external_call_function>')
def test_something(self, mock_external_call):
mock_external_call.return_value = {"example": "response"}
# ... call the view/endpoint under test and assert on the resultIf tests create files (uploads, generated PDFs, images), point MEDIA_ROOT at a temp
directory so test runs don't pollute the real media/ folder, and clean it up after:
import shutil
import tempfile
from django.test import override_settings
TEMP_MEDIA_ROOT = tempfile.mkdtemp()
@override_settings(MEDIA_ROOT=TEMP_MEDIA_ROOT)
class MyTestCase(APITestCase):
@classmethod
def tearDownClass(cls):
super().tearDownClass()
shutil.rmtree(TEMP_MEDIA_ROOT, ignore_errors=True)-
python manage.py makemigrations --check— no missing migrations -
python manage.py test— full suite passes - New endpoints/permissions have at least: an "unauthorized/forbidden" case, a "happy path" case, and one "not found / bad input" case
Once the server is running, access the API documentation:
- Swagger UI:
http://127.0.0.1:8000/swagger/ - ReDoc:
http://127.0.0.1:8000/redoc/
.
├── common/ # Common models, serializers, and utilities
├── helpers/ # Helper functions and utilities
├── projectile/ # Main project configuration
├── user/ # User management app
├── cache/ # Cache directory
├── manage.py # Django management script
├── requirements.txt # Python dependencies
├── Dockerfile # Docker configuration
├── entrypoint.sh # Docker entrypoint script
└── pytest.ini # Pytest configuration
python manage.py collectstaticpython manage.py startapp <app_name>For production deployment:
- Set
DEBUG=Falsein your.envfile - Generate a strong
SECRET_KEY - Configure a PostgreSQL database
- Set appropriate
CORS_ALLOWED_ORIGINSandCSRF_TRUSTED_ORIGINS - Use a production-grade server like Gunicorn:
gunicorn projectile.wsgi --access-logfile - -w 4 -b 0.0.0.0:8000See the LICENSE file for details.
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request