Skip to content

Commit 9556427

Browse files
committed
Add django-debug-toolbar setup.
1 parent 6673794 commit 9556427

File tree

9 files changed

+126
-19
lines changed

9 files changed

+126
-19
lines changed

README.md

+10-9
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
* [Reading list](#reading-list)
2828
- [Example List API](#example-list-api)
2929
- [File uploads](#file-uploads)
30-
- [Helpful commands for local development without docker-compose](#helpful-commands-for-local-development-without-docker-compose)
31-
- [Helpful commands for local development with docker-compose](#helpful-commands-for-local-development-with-docker-compose)
30+
- [Helpful commands for local development without `docker compose`](#helpful-commands-for-local-development-without-docker-compose)
31+
- [Helpful commands for local development with `docker compose`](#helpful-commands-for-local-development-with-docker-compose)
3232
- [Deployment](#deployment)
3333
* [Heroku](#heroku)
3434
* [Render](#render)
@@ -46,7 +46,7 @@ The structure is inspired by [cookiecutter-django](https://github.com/pydanny/co
4646
Few important things:
4747

4848
- Linux / Ubuntu is our primary OS and things are tested for that.
49-
- It's dockerized for local development with `docker-compose`.
49+
- It's dockerized for local development with `docker compose`.
5050
- It uses Postgres as the primary database.
5151
- It comes with [`whitenoise`](http://whitenoise.evans.io/en/stable/) setup, even for local development.
5252
- It comes with [`mypy`](https://mypy.readthedocs.io/en/stable/) configured, using both <https://github.com/typeddjango/django-stubs> and <https://github.com/typeddjango/djangorestframework-stubs/>
@@ -56,6 +56,7 @@ Few important things:
5656
- It comes with GitHub Actions support, [based on that article](https://hacksoft.io/github-actions-in-action-setting-up-django-and-postgres/)
5757
- It can be easily deployed to Heroku, Render or AWS ECS.
5858
- It comes with an example list API, that uses [`django-filter`](https://django-filter.readthedocs.io/en/stable/) for filtering & pagination from DRF.
59+
- It comes with setup for [Django Debug Toolbar](https://django-debug-toolbar.readthedocs.io/en/latest/)
5960
- It comes with examples for writing tests with fakes & factories, based on the following articles - <https://www.hacksoft.io/blog/improve-your-tests-django-fakes-and-factories>, <https://www.hacksoft.io/blog/improve-your-tests-django-fakes-and-factories-advanced-usage>
6061

6162
## General API Stuff
@@ -249,7 +250,7 @@ Currently, the following is supported:
249250

250251
Feel free to use this as the basis of your file upload needs.
251252

252-
## Helpful commands for local development without docker-compose
253+
## Helpful commands for local development without `docker compose`
253254

254255
To create Postgres database:
255256

@@ -275,24 +276,24 @@ To start Celery Beat:
275276
celery -A styleguide_example.tasks beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
276277
```
277278

278-
## Helpful commands for local development with docker-compose
279+
## Helpful commands for local development with `docker compose`
279280

280281
To build and run everything
281282

282283
```
283-
docker-compose up
284+
docker compose up
284285
```
285286

286287
To run migrations
287288

288289
```
289-
docker-compose run django python manage.py migrate
290+
docker compose run django python manage.py migrate
290291
```
291292

292293
To shell
293294

294295
```
295-
docker-compose run django python manage.py shell
296+
docker compose run django python manage.py shell
296297
```
297298

298299
## Deployment
@@ -413,4 +414,4 @@ build:
413414
In order to test if your local setup is up to date, you can either:
414415

415416
1. Try making a commit, to see if `pre-commit` is going to be triggered.
416-
1. Or run `black --check .` and `isort --check .` in the project root directory.
417+
1. Or run `black --check .` and `isort --check .` in the project root directory.

config/django/base.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
SECRET_KEY = "=ug_ucl@yi6^mrcjyz%(u0%&g2adt#bz3@yos%#@*t#t!ypx=a"
2424

2525
# SECURITY WARNING: don't run with debug turned on in production!
26-
DEBUG = True
26+
DEBUG = env.bool("DJANGO_DEBUG", default=True)
2727

2828
ALLOWED_HOSTS = ["*"]
2929

@@ -181,3 +181,8 @@
181181
from config.settings.jwt import * # noqa
182182
from config.settings.sentry import * # noqa
183183
from config.settings.sessions import * # noqa
184+
185+
from config.settings.debug_toolbar.settings import * # noqa
186+
from config.settings.debug_toolbar.setup import DebugToolbarSetup # noqa
187+
188+
INSTALLED_APPS, MIDDLEWARE = DebugToolbarSetup.do_settings(INSTALLED_APPS, MIDDLEWARE)

config/django/test.py

+9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
import os
2+
3+
# This is extremely "eye-poking",
4+
# but we need it, if we want to ignore the debug toolbar in tests
5+
# This is needed because of the way we setup Django Debug Toolbar.
6+
# Since we import base settings, the entire setup will be done, before we have any chance to change it.
7+
# A different way of approaching this would be to have a separate set of env variables for tests.
8+
os.environ.setdefault("DEBUG_TOOLBAR_ENABLED", "False")
9+
110
from .base import * # noqa
211

312
# Based on https://www.hacksoft.io/blog/optimize-django-build-to-run-faster-on-github-actions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from config.env import env
2+
3+
DEBUG_TOOLBAR_ENABLED = env.bool("DEBUG_TOOLBAR_ENABLED", default=True)
4+
DEBUG_TOOLBAR_CONFIG = {"SHOW_TOOLBAR_CALLBACK": "config.settings.debug_toolbar.setup.show_toolbar"}
+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import logging
2+
3+
from django.urls import include, path
4+
5+
logger = logging.getLogger("configuration")
6+
7+
8+
def show_toolbar(*args, **kwargs) -> bool:
9+
"""
10+
The general idea is the following:
11+
12+
1. We show the toolbar if we have it installed & we have it configured to be shown.
13+
- This opens up the option to move the dependency as a local one, if one chooses to do so.
14+
2. This function acts as the single source of truth of that.
15+
- No additional checks elsewhere are required.
16+
17+
This means we can have the following options possible:
18+
19+
- Show on a production environments.
20+
- Exclude the entire dependency from production environments.
21+
- Have the flexibility to control the debug toolbar via a single Django setting.
22+
23+
Additionally, we don't want to deal with the INTERNAL_IPS thing.
24+
"""
25+
from .settings import DEBUG_TOOLBAR_ENABLED
26+
27+
if not DEBUG_TOOLBAR_ENABLED:
28+
return False
29+
30+
try:
31+
import debug_toolbar # noqa
32+
except ImportError:
33+
logger.info("No installation found for: django_debug_toolbar")
34+
return False
35+
36+
return True
37+
38+
39+
class DebugToolbarSetup:
40+
"""
41+
We use a class, just for namespacing convenience.
42+
"""
43+
44+
@staticmethod
45+
def do_settings(INSTALLED_APPS, MIDDLEWARE, middleware_position=None):
46+
_show_toolbar: bool = show_toolbar()
47+
logger.info(f"Django Debug Toolbar in use: {_show_toolbar}")
48+
49+
if not _show_toolbar:
50+
return INSTALLED_APPS, MIDDLEWARE
51+
52+
INSTALLED_APPS = INSTALLED_APPS + ["debug_toolbar"]
53+
54+
# In order to deal with that:
55+
# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#add-the-middleware
56+
# The order of MIDDLEWARE is important.
57+
# You should include the Debug Toolbar middleware as early as possible in the list.
58+
# However, it must come after any other middleware that encodes the response’s content, such as GZipMiddleware.
59+
# We support inserting the middleware at an arbitrary position in the list.
60+
# If position is not specified, we will just include it at the end of the list.
61+
62+
debug_toolbar_middleware = "debug_toolbar.middleware.DebugToolbarMiddleware"
63+
64+
if middleware_position is None:
65+
MIDDLEWARE = MIDDLEWARE + [debug_toolbar_middleware]
66+
else:
67+
# Grab a new copy of the list, since insert mutates the internal structure
68+
_middleware = MIDDLEWARE[::]
69+
_middleware.insert(middleware_position, debug_toolbar_middleware)
70+
71+
MIDDLEWARE = _middleware
72+
73+
return INSTALLED_APPS, MIDDLEWARE
74+
75+
@staticmethod
76+
def do_urls(urlpatterns):
77+
if not show_toolbar():
78+
return urlpatterns
79+
80+
import debug_toolbar # noqa
81+
82+
return urlpatterns + [path("__debug__/", include(debug_toolbar.urls))]

config/urls.py

+4
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,7 @@
2222
path("admin/", admin.site.urls),
2323
path("api/", include(("styleguide_example.api.urls", "api"))),
2424
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
25+
26+
from config.settings.debug_toolbar.setup import DebugToolbarSetup # noqa
27+
28+
urlpatterns = DebugToolbarSetup.do_urls(urlpatterns)

pyproject.toml

+9
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,12 @@ line-length = 120
33
# By default, `black` will ignore skip configuration when paths are explicitly provided.
44
# In order for `pre-commit` to respect this configuration, `force-exclude` needs to be explicitly set.
55
force-exclude = 'migrations'
6+
7+
[tool.isort]
8+
# https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html#isort
9+
profile = "black"
10+
# By default, `isort` will ignore skip configuration when paths are explicitly provided.
11+
# In order for `pre-commit` to respect this configuration, `filter_files` needs to be set to true.
12+
# https://jugmac00.github.io/blog/isort-and-pre-commit-a-friendship-with-obstacles/
13+
filter_files = true
14+
skip_glob = ["*/migrations/*", "config/*"]

requirements/local.txt

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ Faker==15.1.1
99
ipdb==0.13.9
1010
ipython==8.6.0
1111

12+
django-debug-toolbar==3.8.1
13+
1214
mypy==0.991
1315

1416
django-stubs==1.14.0

setup.cfg

-9
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,3 @@ exclude =
66
.git,
77
__pycache__,
88
*/migrations/*
9-
10-
[isort]
11-
# https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html#isort
12-
profile = black
13-
# By default, `isort` will ignore skip configuration when paths are explicitly provided.
14-
# In order for `pre-commit` to respect this configuration, `filter_files` needs to be set to true.
15-
# https://jugmac00.github.io/blog/isort-and-pre-commit-a-friendship-with-obstacles/
16-
filter_files = true
17-
skip_glob = */migrations/*

0 commit comments

Comments
 (0)