Skip to content

Commit 25b0c77

Browse files
feat: add debug mode support for Django with VS Code integration (#158)
* feat: add debug mode support for Django with VS Code integration * refactor: remove outdated VS Code Docker tasks and update debugpy version to 1.8.14 * refactor: remove unused import of CommandError in runserver_debug.py * refactor: add a blank line for improved readability in runserver_debug.py
1 parent 55a6f68 commit 25b0c77

File tree

5 files changed

+134
-2
lines changed

5 files changed

+134
-2
lines changed

.vscode/launch.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"name": "Python: Remote Attach (Django in Docker)",
6+
"type": "debugpy",
7+
"request": "attach",
8+
"connect": {
9+
"host": "localhost",
10+
"port": 5678
11+
},
12+
"pathMappings": [
13+
{
14+
"localRoot": "${workspaceFolder}",
15+
"remoteRoot": "/app"
16+
}
17+
],
18+
"justMyCode": false,
19+
"django": true,
20+
"subProcess": false
21+
}
22+
]
23+
}

README.md

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,48 @@
104104
5. To fix lint issues
105105
```
106106
ruff check --fix
107-
```
107+
```
108+
109+
## Debug Mode with VS Code
110+
111+
### Prerequisites
112+
- VS Code with Python extension installed
113+
- Docker and docker-compose
114+
115+
### Debug Setup
116+
117+
1. **Start the application with debug mode:**
118+
```
119+
python manage.py runserver_debug 0.0.0.0:8000
120+
```
121+
122+
2. **Available debug options:**
123+
```bash
124+
# Basic debug mode (default debug port 5678)
125+
python manage.py runserver_debug 0.0.0.0:8000
126+
127+
# Custom debug port
128+
python manage.py runserver_debug 0.0.0.0:8000 --debug-port 5679
129+
130+
# Wait for debugger before starting (useful for debugging startup code)
131+
python manage.py runserver_debug 0.0.0.0:8000 --wait-for-client
132+
```
133+
134+
3. **Attach VS Code debugger:**
135+
- Press `F5` or go to `Run > Start Debugging`
136+
- Select `Python: Remote Attach (Django in Docker)` from the dropdown
137+
- Set breakpoints in your Python code
138+
- Make requests to trigger the breakpoints
139+
140+
### Debug Features
141+
- **Debug server port**: 5678 (configurable)
142+
- **Path mapping**: Local code mapped to container paths
143+
- **Django mode**: Special Django debugging features enabled
144+
- **Hot reload**: Code changes reflected immediately
145+
- **Variable inspection**: Full debugging capabilities in VS Code
146+
147+
### Troubleshooting
148+
- If port 5678 is in use, specify a different port with `--debug-port`
149+
- Ensure VS Code Python extension is installed
150+
- Check that breakpoints are set in the correct files
151+
- Verify the debug server shows "Debug server listening on port 5678"

docker-compose.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,22 @@ services:
22
django-app:
33
build: .
44
container_name: todo-django-app
5-
command: python manage.py runserver 0.0.0.0:8000
5+
command: python -Xfrozen_modules=off manage.py runserver_debug 0.0.0.0:8000 --debug-port 5678
66
environment:
77
MONGODB_URI: mongodb://db:27017
88
DB_NAME: todo-app
9+
PYTHONUNBUFFERED: 1
10+
PYDEVD_DISABLE_FILE_VALIDATION: 1
911
volumes:
1012
- .:/app
1113
ports:
1214
- "8000:8000"
15+
- "5678:5678" # Debug port
1316
depends_on:
1417
- db
1518
- mongo-init
19+
stdin_open: true
20+
tty: true
1621

1722
db:
1823
image: mongo:latest

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ requests==2.32.3
2727
email-validator==2.2.0
2828
testcontainers[mongodb]==4.10.0
2929
drf-spectacular==0.28.0
30+
debugpy==1.8.14
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import debugpy
2+
import socket
3+
from django.core.management.commands.runserver import Command as RunServerCommand
4+
5+
6+
class Command(RunServerCommand):
7+
help = "Run the Django development server with debugpy for VS Code debugging"
8+
9+
def add_arguments(self, parser):
10+
super().add_arguments(parser)
11+
parser.add_argument("--debug-port", type=int, default=5678, help="Port for the debug server (default: 5678)")
12+
parser.add_argument(
13+
"--wait-for-client", action="store_true", help="Wait for debugger client to attach before starting server"
14+
)
15+
16+
def is_port_in_use(self, port):
17+
"""Check if a port is already in use"""
18+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
19+
try:
20+
s.bind(("0.0.0.0", port))
21+
return False
22+
except OSError:
23+
return True
24+
25+
def handle(self, *args, **options):
26+
debug_port = options.get("debug_port", 5678)
27+
wait_for_client = options.get("wait_for_client", False)
28+
29+
# Check if debugpy is already initialized or connected
30+
if debugpy.is_client_connected():
31+
self.stdout.write(self.style.WARNING(f"Debugger already connected on port {debug_port}"))
32+
else:
33+
# Check if debug port is in use
34+
if self.is_port_in_use(debug_port):
35+
self.stdout.write(self.style.ERROR(f"Port {debug_port} is already in use. Debug server not started."))
36+
self.stdout.write(self.style.WARNING("Django server will start without debug capability."))
37+
else:
38+
try:
39+
# Only configure debugpy if not already configured
40+
if not hasattr(debugpy, "_is_configured") or not debugpy._is_configured:
41+
# Listen for debugger connections
42+
debugpy.listen(("0.0.0.0", debug_port))
43+
self.stdout.write(self.style.SUCCESS(f"Debug server listening on port {debug_port}"))
44+
45+
if wait_for_client:
46+
self.stdout.write(self.style.WARNING("Waiting for debugger client to attach..."))
47+
debugpy.wait_for_client()
48+
self.stdout.write(self.style.SUCCESS("Debugger client attached!"))
49+
else:
50+
self.stdout.write(self.style.SUCCESS("Server starting - you can now attach the debugger"))
51+
else:
52+
self.stdout.write(self.style.WARNING("Debug server already configured"))
53+
54+
except Exception as e:
55+
self.stdout.write(self.style.ERROR(f"Failed to start debug server: {str(e)}"))
56+
self.stdout.write(self.style.WARNING("Django server will start without debug capability."))
57+
58+
# Call the parent runserver command
59+
super().handle(*args, **options)

0 commit comments

Comments
 (0)