Skip to content

Commit 2bd42d6

Browse files
salomvarytim-schilling
authored andcommitted
Add asynchronous examples (#1819)
1 parent 46efd5d commit 2bd42d6

File tree

6 files changed

+95
-2
lines changed

6 files changed

+95
-2
lines changed

example/README.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,13 @@ environment variable::
4646

4747
$ DB_BACKEND=postgresql python example/manage.py migrate
4848
$ DB_BACKEND=postgresql python example/manage.py runserver
49+
50+
Using an asynchronous (ASGI) server:
51+
52+
Install [Daphne](https://pypi.org/project/daphne/) first:
53+
54+
$ python -m pip install daphne
55+
56+
Then run the Django development server:
57+
58+
$ ASYNC_SERVER=true python example/manage.py runserver

example/asgi.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""ASGI config for example project."""
2+
3+
import os
4+
5+
from django.core.asgi import get_asgi_application
6+
7+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings")
8+
9+
application = get_asgi_application()

example/settings.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
# Application definition
1919

2020
INSTALLED_APPS = [
21+
*(["daphne"] if os.getenv("ASYNC_SERVER", False) else []), # noqa: FBT003
2122
"django.contrib.admin",
2223
"django.contrib.auth",
2324
"django.contrib.contenttypes",
@@ -66,6 +67,7 @@
6667
USE_TZ = True
6768

6869
WSGI_APPLICATION = "example.wsgi.application"
70+
ASGI_APPLICATION = "example.asgi.application"
6971

7072

7173
# Cache and database
@@ -103,7 +105,6 @@
103105

104106
STATICFILES_DIRS = [os.path.join(BASE_DIR, "example", "static")]
105107

106-
107108
# Only enable the toolbar when we're in debug mode and we're
108109
# not running tests. Django will change DEBUG to be False for
109110
# tests, so we can't rely on DEBUG alone.
@@ -117,3 +118,26 @@
117118
]
118119
# Customize the config to support turbo and htmx boosting.
119120
DEBUG_TOOLBAR_CONFIG = {"ROOT_TAG_EXTRA_ATTRS": "data-turbo-permanent hx-preserve"}
121+
122+
LOGGING = {
123+
"version": 1,
124+
"disable_existing_loggers": False,
125+
"handlers": {
126+
"console": {
127+
"class": "logging.StreamHandler",
128+
},
129+
},
130+
"root": {
131+
"handlers": ["console"],
132+
"level": "WARNING",
133+
},
134+
"loggers": {
135+
# Log when an asynchronous handler is adapted for middleware.
136+
# See warning here: https://docs.djangoproject.com/en/4.2/topics/async/#async-views
137+
"django.request": {
138+
"handlers": ["console"],
139+
"level": os.getenv("DJANGO_REQUEST_LOG_LEVEL", "INFO"),
140+
"propagate": False,
141+
},
142+
},
143+
}

example/templates/async_db.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta http-equiv="content-type" content="text/html; charset=utf-8">
5+
<title>Async DB</title>
6+
</head>
7+
<body>
8+
<h1>Async DB</h1>
9+
<p>
10+
<span>Value </span>
11+
<span>{{ user_count }}</span>
12+
</p>
13+
</body>
14+
</html>

example/urls.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@
33
from django.views.generic import TemplateView
44

55
from debug_toolbar.toolbar import debug_toolbar_urls
6-
from example.views import increment, jinja2_view
6+
from example.views import (
7+
async_db,
8+
async_db_concurrent,
9+
async_home,
10+
increment,
11+
jinja2_view,
12+
)
713

814
urlpatterns = [
915
path("", TemplateView.as_view(template_name="index.html"), name="home"),
@@ -13,6 +19,9 @@
1319
name="bad_form",
1420
),
1521
path("jinja/", jinja2_view, name="jinja"),
22+
path("async/", async_home, name="async_home"),
23+
path("async/db/", async_db, name="async_db"),
24+
path("async/db-concurrent/", async_db_concurrent, name="async_db_concurrent"),
1625
path("jquery/", TemplateView.as_view(template_name="jquery/index.html")),
1726
path("mootools/", TemplateView.as_view(template_name="mootools/index.html")),
1827
path("prototype/", TemplateView.as_view(template_name="prototype/index.html")),

example/views.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import asyncio
2+
3+
from asgiref.sync import sync_to_async
4+
from django.contrib.auth.models import User
15
from django.http import JsonResponse
26
from django.shortcuts import render
37

@@ -13,3 +17,26 @@ def increment(request):
1317

1418
def jinja2_view(request):
1519
return render(request, "index.jinja", {"foo": "bar"}, using="jinja2")
20+
21+
22+
async def async_home(request):
23+
return await sync_to_async(render)(request, "index.html")
24+
25+
26+
async def async_db(request):
27+
user_count = await User.objects.acount()
28+
29+
return await sync_to_async(render)(
30+
request, "async_db.html", {"user_count": user_count}
31+
)
32+
33+
34+
async def async_db_concurrent(request):
35+
# Do database queries concurrently
36+
(user_count, _) = await asyncio.gather(
37+
User.objects.acount(), User.objects.filter(username="test").acount()
38+
)
39+
40+
return await sync_to_async(render)(
41+
request, "async_db.html", {"user_count": user_count}
42+
)

0 commit comments

Comments
 (0)