I'm trying to run my fastapi code on daphne webserver instead of uvicorn, because my end goal is to run it on Android, where uvicorn is not available. I've been debugging my app for hours at this point. Setting it all up. Here is my code:
settings.py
"""
Django settings for myproject project.
Generated by 'django-admin startproject' using Django 3.2.6.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-_n5hy*-sk6y0&mcgu6&_s*+ql5fvujw+ndccjobc0g8lryx!^z'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'myproject.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'myproject.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
ALLOWED_HOSTS = ['*'] #my change
ROOT_URLCONF = "myproject.urlconf" #my change
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
urlconf.py
from django.urls import path
import views
urlpatterns = [
path('coordinates/', views.main),
]
views.py
from fastapi import FastAPI
from datetime import datetime
from pydantic import BaseModel
from fastapi.middleware.cors import CORSMiddleware
def main(response):
app = FastAPI()
origins = ["*"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.post("/") #get
def root():
return {"message": "Hello World"}
directionX = 0
directionY = 0
Gas = 0
@app.get("/coordinates/") #post is used to get data, but I can send it using get and query parameters response_model=Item)
def getcoordinates(direction_x,direction_y,gas): #http://127.0.0.1:8000/coordinates/?direction_x=0&direction_y=10&gas=50
global directionX,directionY, Gas #changed async def to def
directionX = direction_x
directionY = direction_y
Gas = gas
return {"data":(direction_x,direction_y,gas)}
return HttpResponse(status=200) #works, ok
asgi.py
"""
ASGI config for myproject project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') #myproject.settings
application = get_asgi_application()
Terminal commands to launch the files:
daphne -b 0.0.0.0 -p 8000 myproject.asgi:application
The error log when I visit http://0.0.0.0:8000/coordinates in my browser:
2021-08-23 14:00:35,107 INFO Starting server at tcp:port=8000:interface=0.0.0.0
2021-08-23 14:00:35,108 INFO HTTP/2 support not enabled (install the http2 and tls Twisted extras)
2021-08-23 14:00:35,108 INFO Configuring endpoint tcp:port=8000:interface=0.0.0.0
2021-08-23 14:00:35,109 INFO Listening on TCP address 0.0.0.0:8000
Internal Server Error: /coordinates/
Traceback (most recent call last):
File "/home/petr/.local/lib/python3.8/site-packages/asgiref/sync.py", line 482, in thread_handler
raise exc_info[1]
File "/home/petr/.local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 38, in inner
response = await get_response(request)
File "/home/petr/.local/lib/python3.8/site-packages/django/utils/deprecation.py", line 135, in __acall__
response = await sync_to_async(
File "/home/petr/.local/lib/python3.8/site-packages/asgiref/sync.py", line 444, in __call__
ret = await asyncio.wait_for(future, timeout=None)
File "/usr/lib/python3.8/asyncio/tasks.py", line 455, in wait_for
return await fut
File "/usr/lib/python3.8/concurrent/futures/thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "/home/petr/.local/lib/python3.8/site-packages/asgiref/sync.py", line 486, in thread_handler
return func(*args, **kwargs)
File "/home/petr/.local/lib/python3.8/site-packages/django/middleware/clickjacking.py", line 26, in process_response
if response.get('X-Frame-Options') is not None:
AttributeError: 'ASGIRequest' object has no attribute 'get'
2021-08-23 14:00:45,987 ERROR Internal Server Error: /coordinates/
Traceback (most recent call last):
File "/home/petr/.local/lib/python3.8/site-packages/asgiref/sync.py", line 482, in thread_handler
raise exc_info[1]
File "/home/petr/.local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 38, in inner
response = await get_response(request)
File "/home/petr/.local/lib/python3.8/site-packages/django/utils/deprecation.py", line 135, in __acall__
response = await sync_to_async(
File "/home/petr/.local/lib/python3.8/site-packages/asgiref/sync.py", line 444, in __call__
ret = await asyncio.wait_for(future, timeout=None)
File "/usr/lib/python3.8/asyncio/tasks.py", line 455, in wait_for
return await fut
File "/usr/lib/python3.8/concurrent/futures/thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "/home/petr/.local/lib/python3.8/site-packages/asgiref/sync.py", line 486, in thread_handler
return func(*args, **kwargs)
File "/home/petr/.local/lib/python3.8/site-packages/django/middleware/clickjacking.py", line 26, in process_response
if response.get('X-Frame-Options') is not None:
AttributeError: 'ASGIRequest' object has no attribute 'get'
127.0.0.1:58158 - - [23/Aug/2021:14:00:45] "GET /coordinates/" 500 76195
Not Found: /favicon.ico
2021-08-23 14:00:46,611 WARNING Not Found: /favicon.ico
127.0.0.1:58158 - - [23/Aug/2021:14:00:46] "GET /favicon.ico" 404 2120
Big thanks to anyone who can help me with this!
Daphne is maintained by the Django project, but you can install it by itself. To install it, first switch into your virtual environment if you're using one, then run:
python -m pip install daphne
Then remove the FastAPI code from the Django views into it's own file, e.g. main.py
from fastapi import FastAPI
from datetime import datetime
from pydantic import BaseModel
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = ["*"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.post("/") #get
def root():
return {"message": "Hello World"}
...
Now, if you switch into the same directory as your main.py
, you can run your file with:
daphne -b 0.0.0.0 -p 8000 main:app