Skip to main content

Build FastAPI app top of Django

Project description

Django FastAPI Bridge

Allows to use FastAPI top of Django

Rationale

  • Use Django as a core for your app logic, admin panel and multiple addons available for years ("batteries included"), then create a web interface with FastAPI ("batteries also included")
  • Add a web interface built with FastAPI to your existing Django project, until you migrate it to fully ASGI compatible application
  • Automatically create documentation and OpenAPI schema with FastAPI
  • Both Django and FastAPI are mature, stable, supported and well known products with large communities. No need to use other tools nor rely on less or more similar clones.
  • Eventually run the same Django project in full ASGI mode to enable async features like long-polling (although you must carefully prepare your project for such cases)

TODO

  • Initial ASGI support
  • WSGI support
  • Authentication and authorization bridge
  • Utils for serialization and updating ORM models
  • Exception handler for DEBUG mode
  • Replacement for most common shortcut / helpers
  • Tests and stabilization

Quickstart

Install FastAPI:

pip install fastapi

Install required packages:

pip install django-fastapi-bridge

Add django_fastapi to INSTALLED_APPS in your settings.py file:

INSTALLED_APPS = [
    # ...
    "django_fastapi",
    # ...
]

Set ASGI_APPLICATION and WSGI_APPLICATION in your settings.py file:

ASGI_APPLICATION = "django_fastapi.asgi.application"
WSGI_APPLICATION = "django_fastapi.wsgi.application"

Development server (WSGI)

Use Django's runserver command as usual

Notes:

  • ASGI app is wrapped to WSGI interface through a2wsgi.ASGIMiddleware
  • Django's runserver will not print tracebacks to the stdout and tracebacks aren't generated by FastAPI/Bridge (this should be addressed later)

Development server (ASGI w/Daphne)

Install daphne, then add daphne to the INSTALLED_APPS before django.core.staticfiles.

Run development server:

python manage.py runserver

Production server (ASGI w/Uvicorn)

Install Uvicorn:

pip install uvicorn

Run uvicorn:

DJANGO_SETTINGS_MODULE=yourproject.settings uvicorn django_fastapi.asgi:application

Production server (WSGI w/Uvicorn, not recommended)

Install Uvicorn:

pip install uvicorn

Run uvicorn:

DJANGO_SETTINGS_MODULE=yourproject.settings uvicorn --interface wsgi django_fastapi.wsgi:application

Running the application in WSGI mode will be safest than in ASGI mode, which relies on protections built into Django, but the overall performance can be more than twice as low.

Configuration

Base settings

To configure default FastAPI instance you can use these settings:

  • FASTAPI_TITLE: set's API title [FastAPI(title=FASTAPI_TITLE)]
  • FASTAPI_VERSION: set's API version [FastAPI(version=FASTAPI_VERSION)]
  • FASTAPI_ROOT_PATH: set's API root path [FastAPI(root_path=FASTAPI_ROOT_PATH)]

CORS

  • FASTAPI_CORS_ENABLED: if True, adds CORS middleware to the default FastAPI instance (disabled by default)
  • FASTAPI_CORS_ALLOW_ORIGINS: defaults to ["*"]
  • FASTAPI_CORS_ALLOW_CREDENTIALS: defaults to True
  • FASTAPI_CORS_ALLOW_METHODS: defaults to ["*"]
  • FASTAPI_CORS_ALLOW_HEADERS: defaults to ["*"]

Autodiscover

  • FASTAPI_AUTODISCOVER: if True, Django FastAPI will automatically import FASTAPI_AUTODISCOVER_MODULES from your INSTALLED_APPS. Default: True
  • FASTAPI_AUTODISCOVER_MODULES: defaults to ["api"]

Examples and performance

See example/test_api/api.py for more examples

Querying a database in sync mode

Write your handler as usual:

@api.get("/permissions", response_model=PermissionListResource)
def permissions_list():
    queryset = Permission.objects.all()
    items = [{"pk": obj.pk, "name": obj.name} for obj in queryset]
    return PermissionListResource(items=items)

Querying a database in async mode

Prepend your function with async keyword and query the database in an async way. Because QuerySet is a lazy evaluated object, it will hit the database during creating list of items. That's why you must use async for in the list comprehension:

@api.get("/async/permissions", response_model=PermissionListResource)
async def permissions_list():
    queryset = Permission.objects.all()
    items = [{"pk": obj.pk, "name": obj.name} async for obj in queryset]
    return PermissionListResource(items=items)

Performance comparison

Sync mode:

Concurrency Level:      10
Time taken for tests:   15.217 seconds
Complete requests:      10000
Failed requests:        0
Requests per second:    657.16 [#/sec] (mean)
Time per request:       15.217 [ms] (mean)

Async mode:

Concurrency Level:      10
Time taken for tests:   6.374 seconds
Complete requests:      10000
Failed requests:        0
Requests per second:    1568.97 [#/sec] (mean)

Testing platform:

Machine:
  Type: Desktop Mobo: Micro-Star model: B550-A PRO (MS-7C56) v: 2.0
Memory:
  System RAM: total: 32 GiB available: 31.27 GiB used: 9.44 GiB (30.2%)
CPU:
  Info: 12-core model: AMD Ryzen 9 5900X bits: 64 type: MT MCP cache:
    L2: 6 MiB
  Speed (MHz): avg: 2425 min/max: 2200/4950 cores: 1: 3598 2: 2869 3: 2874
    4: 2200 5: 2819 6: 2200 7: 2200 8: 2200 9: 2200 10: 2200 11: 2199 12: 2199
    13: 3584 14: 2200 15: 2879 16: 2200 17: 2200 18: 2200 19: 2200 20: 2200
    21: 2200 22: 2200 23: 2200 24: 2200

Server command:

cd example
DJANGO_SETTINGS_MODULE=fastapi_bridge_test.settings uvicorn django_fastapi.asgi:application

Software versions:

  • Python 3.11.3
  • Django 4.2.5
  • Linux 6.1.49-1-MANJARO

Important notes

With the bridge a typical Django's server stack (middlewares, requests, responses) will not be used. This causes some incompatibilities, but in a this should not be an issue while building HTTP APIs top of Django:

  • The interface of FastAPI callbacks will never be same as Django's views interface (i.e. no mandatory request argument)
  • The request object used will be FastAPI/Starlette's Request object, not Django one
  • Django middlewares can't be used directly
  • Context processors based on request objects will mostly fail
  • All helpers / shortcut functions based on Django's original request will not work
  • Your application can run in synchronous mode with a potential performance cost, until you use fully async code (see "Why this works" notes below). NB: This is similar how all alternatives based on ASGI protocol works.

Why this works

This bridge disables Django's HTTP server and uses FastAPI/Starlette directly. At this moment Django has partial but stable support for the asynchonous mode, and for a compatibility reasons it can switch between sync and asynchronous mode automatically. In cases where you are mixing sync and async calls, you must wrap them with async_to_sync or sync_to_async from asgiref.sync module.

Current versions of Django (4.1+) handles unsafe non-async calls very nicely, so there are no errors known from the past. Django's async-unsafe parts are protected from execution in async environment and will raise SynchronousOnlyOperation exception. In case of third party apps/addons you must make sure they're async-safe or protected.

Please note that switching between sync and async modes comes at a cost. Although Django tries to optimize the number of context switches, in some configurations there may be more than one, which may result in a performance penalty.

More details can be found in the Django documentation: https://docs.djangoproject.com/en/4.2/topics/async/

Alternatives

  • Django Ninja - REST framework for Django inspired by FastAPI

License

ISC

Copyright 2023 Marcin Nowak <marcin.j.nowak.gmail.com>

Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-fastapi-bridge-0.2.tar.gz (10.7 kB view hashes)

Uploaded Source

Built Distribution

django_fastapi_bridge-0.2-py3-none-any.whl (9.0 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page