Skip to content

Commit ec2b98d

Browse files
committed
Add django+subscriptions example
1 parent d668ccb commit ec2b98d

File tree

14 files changed

+921
-0
lines changed

14 files changed

+921
-0
lines changed

django-subscriptions/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
run:
2+
poetry run uvicorn demo.asgi:application --reload --debug

django-subscriptions/api/__init__.py

Whitespace-only changes.

django-subscriptions/api/asgi.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from strawberry.asgi import GraphQL
2+
3+
4+
class MyGraphQL(GraphQL):
5+
...

django-subscriptions/api/schema.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import asyncio
2+
3+
import strawberry
4+
5+
6+
@strawberry.type
7+
class Query:
8+
@strawberry.field
9+
def hello() -> str:
10+
return "world"
11+
12+
13+
@strawberry.type
14+
class Subscription:
15+
@strawberry.subscription
16+
async def count(self, target: int = 100) -> int:
17+
for i in range(target):
18+
yield i
19+
await asyncio.sleep(0.5)
20+
21+
22+
schema = strawberry.Schema(query=Query, subscription=Subscription)

django-subscriptions/api/urls.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.urls import path
2+
3+
from .schema import schema
4+
from .views import AsyncGraphQLView
5+
6+
urlpatterns = [path("graphql", AsyncGraphQLView.as_view(schema=schema))]

django-subscriptions/api/views.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import os
2+
3+
import strawberry
4+
from django.http import Http404, HttpRequest
5+
from django.template import RequestContext, Template
6+
from django.template.exceptions import TemplateDoesNotExist
7+
from django.template.loader import render_to_string
8+
from django.template.response import TemplateResponse
9+
from strawberry.django.views import AsyncGraphQLView as StrawberryAsyncGraphQLView
10+
11+
12+
class AsyncGraphQLView(StrawberryAsyncGraphQLView):
13+
def _render_graphiql(self, request: HttpRequest, context=None):
14+
if not self.graphiql:
15+
raise Http404()
16+
17+
try:
18+
template = Template(render_to_string("graphql/graphiql.html"))
19+
except TemplateDoesNotExist:
20+
template = Template(
21+
open(
22+
os.path.join(
23+
os.path.dirname(os.path.abspath(strawberry.__file__)),
24+
"static/graphiql.html",
25+
),
26+
"r",
27+
).read()
28+
)
29+
30+
context = context or {}
31+
# THIS enables subscriptions
32+
context.update({"SUBSCRIPTION_ENABLED": "true"})
33+
34+
response = TemplateResponse(request=request, template=None, context=context)
35+
response.content = template.render(RequestContext(request, context))
36+
37+
return response

django-subscriptions/demo/__init__.py

Whitespace-only changes.

django-subscriptions/demo/asgi.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import os
2+
3+
from api.asgi import MyGraphQL
4+
from django.core.asgi import get_asgi_application
5+
from starlette.websockets import WebSocketDisconnect
6+
7+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings")
8+
9+
django_application = get_asgi_application()
10+
11+
12+
async def application(scope, receive, send):
13+
# TODO: always use ASGI graphql
14+
15+
if scope["type"] == "http":
16+
await django_application(scope, receive, send)
17+
elif scope["type"] == "websocket":
18+
try:
19+
from api.schema import schema
20+
21+
graphql_app = MyGraphQL(schema, keep_alive=True, keep_alive_interval=5)
22+
23+
await graphql_app(scope, receive, send)
24+
except WebSocketDisconnect:
25+
pass
26+
else:
27+
raise NotImplementedError(f"Unknown scope type {scope['type']}")

django-subscriptions/demo/settings.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
"""
2+
Django settings for demo project.
3+
4+
Generated by 'django-admin startproject' using Django 3.1.7.
5+
6+
For more information on this file, see
7+
https://docs.djangoproject.com/en/3.1/topics/settings/
8+
9+
For the full list of settings and their values, see
10+
https://docs.djangoproject.com/en/3.1/ref/settings/
11+
"""
12+
13+
from pathlib import Path
14+
15+
# Build paths inside the project like this: BASE_DIR / 'subdir'.
16+
BASE_DIR = Path(__file__).resolve().parent.parent
17+
18+
19+
# Quick-start development settings - unsuitable for production
20+
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
21+
22+
# SECURITY WARNING: keep the secret key used in production secret!
23+
SECRET_KEY = 'p-h@br&tcqetcsaa%))9%5-80qjv&*-2_@6eddvp!3m)z#kyq%'
24+
25+
# SECURITY WARNING: don't run with debug turned on in production!
26+
DEBUG = True
27+
28+
ALLOWED_HOSTS = []
29+
30+
31+
# Application definition
32+
33+
INSTALLED_APPS = [
34+
'django.contrib.admin',
35+
'django.contrib.auth',
36+
'django.contrib.contenttypes',
37+
'django.contrib.sessions',
38+
'django.contrib.messages',
39+
'django.contrib.staticfiles',
40+
]
41+
42+
MIDDLEWARE = [
43+
'django.middleware.security.SecurityMiddleware',
44+
'django.contrib.sessions.middleware.SessionMiddleware',
45+
'django.middleware.common.CommonMiddleware',
46+
'django.middleware.csrf.CsrfViewMiddleware',
47+
'django.contrib.auth.middleware.AuthenticationMiddleware',
48+
'django.contrib.messages.middleware.MessageMiddleware',
49+
'django.middleware.clickjacking.XFrameOptionsMiddleware',
50+
]
51+
52+
ROOT_URLCONF = 'demo.urls'
53+
54+
TEMPLATES = [
55+
{
56+
'BACKEND': 'django.template.backends.django.DjangoTemplates',
57+
'DIRS': [],
58+
'APP_DIRS': True,
59+
'OPTIONS': {
60+
'context_processors': [
61+
'django.template.context_processors.debug',
62+
'django.template.context_processors.request',
63+
'django.contrib.auth.context_processors.auth',
64+
'django.contrib.messages.context_processors.messages',
65+
],
66+
},
67+
},
68+
]
69+
70+
WSGI_APPLICATION = 'demo.wsgi.application'
71+
72+
73+
# Database
74+
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
75+
76+
DATABASES = {
77+
'default': {
78+
'ENGINE': 'django.db.backends.sqlite3',
79+
'NAME': BASE_DIR / 'db.sqlite3',
80+
}
81+
}
82+
83+
84+
# Password validation
85+
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
86+
87+
AUTH_PASSWORD_VALIDATORS = [
88+
{
89+
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
90+
},
91+
{
92+
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
93+
},
94+
{
95+
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
96+
},
97+
{
98+
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
99+
},
100+
]
101+
102+
103+
# Internationalization
104+
# https://docs.djangoproject.com/en/3.1/topics/i18n/
105+
106+
LANGUAGE_CODE = 'en-us'
107+
108+
TIME_ZONE = 'UTC'
109+
110+
USE_I18N = True
111+
112+
USE_L10N = True
113+
114+
USE_TZ = True
115+
116+
117+
# Static files (CSS, JavaScript, Images)
118+
# https://docs.djangoproject.com/en/3.1/howto/static-files/
119+
120+
STATIC_URL = '/static/'

django-subscriptions/demo/urls.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from django.contrib import admin
2+
from django.urls import include, path
3+
4+
urlpatterns = [
5+
path("admin/", admin.site.urls),
6+
path("", include("api.urls")),
7+
]

0 commit comments

Comments
 (0)