Search code examples
pythondjangofastapidaphne

Getting AttributeError: 'ASGIRequest' object has no attribute 'get' in daphne django


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!


Solution

  • 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