Combine FastAPI with Django ORM

Motivation

It seems that FastAPI has been growing recently with Momentum of Breaking Bamboo.

I want to flirt with FastAPI from Django, but I still want to continue using Django and its user system. It looks greedy, but it's actually such a good thing. This time I'll show you how to combine Django ORM with FastAPI.

Of course, there are also disadvantages. In terms of performance, ORM's Async IO support cannot be used. If you want to improve the performance, you can create a model such as orm separately.

Folder structure

First, let's talk about folder structure. You can create the contents of the folder based on the tutorial in the Django documentation. For details, see here.

$ django-admin startproject mysite
$ django-admin startapp poll

After generating the file, delete views.py and models.py and prepare a folder for FastAPI as shown below.

$ tree -L 3 -I '__pycache__|venv' -P '*.py'
.
├── manage.py
├── mysite
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── polls
    ├── __init__.py
    ├── adapters
    │   └── __init__.py
    ├── admin.py
    ├── apps.py
    ├── migrations
    │   └── __init__.py
    ├── models
    │   └── __init__.py
    ├── routers
    │   └── __init__.py
    ├── schemas
    │   └── __init__.py
    └── tests.py

7 directories, 15 files

Use of each folder properly:

--models folder: Django ORM --routers folder: FastAPI routers --schemas folder: FastAPI Pydantic validator --ʻAdapters` folder: Convert Django ORM to Pydantic validator

Prepare the data

Refer to the Django document and try to enter the data.

>>> from polls.models import Choice, Question
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())
>>> q.save()

Introduced FastAPI

For simplicity, put the example below in the folder __init__.py. Also omit ʻimport`.

schemas

class FastQuestion(BaseModel):
    question_text: str
    pub_date: datetime

    @classmethod
    def from_model(cls, instance: Question):
        return cls(
            id=instance.id,
            question_text=instance.question_text,
            pub_date=instance.pub_date,
        )


class FastQuestions(BaseModel):
    items: List[FastQuestion]

    @classmethod
    def from_qs(cls, qs):
        return cls(items=[FastQuestion.from_model(i) for i in qs])

adapters

ModelT = TypeVar("ModelT", bound=models.Model)


def retieve_object(model_class: Type[ModelT], id: int) -> ModelT:
    instance = model_class.objects.filter(pk=id).first()
    if not instance:
        raise HTTPException(status_code=404, detail="Object not found.")
    return instance


def retrieve_question(
    q_id: int = Path(..., description="retrive question from db")
) -> Question:
    return retieve_object(Question, q_id)


def retrieve_questions():
    return Question.objects.all()

routers

@router.get("/")
def get_questions(
    questions: List[Question] = Depends(adapters.retrieve_questions),
) -> FastQuestions:
    return FastQuestions.from_qs(questions)


@router.get("/{q_id}")
def get_question(
    question: Question = Depends(adapters.retrieve_question),
) -> FastQuestion:
    return FastQuestion.from_model(question)

asgi.py

Added FastAPI App launch to mysite / asgi.py.

from fastapi import FastAPI
from polls.routers import router

fastapp = FastAPI()
fastapp.include_router(router, tags=["questions"], prefix="/question")

Launch

First, create a static file for ʻuvicorn`:

$ python manage.py collectstatic --noinput

FastAPI is started with ʻuvicorn mysite.asgi: fastapp --reload, and Django is started with ʻuvicorn mysite.asgi: application --port 8001 --reload.

Access http://127.0.0.1:8000/docs/ for the FastAPI Doc and http://127.0.0.1:8001/admin/ for the Django admin screen.

Summary

The combination of FastAPI and Django ORM is surprisingly easy, and if you divide the integration part well, you can create a neat folder structure.

The code above can be found on my Github.

Recommended Posts

Combine FastAPI with Django ORM
Combine two images with Django
Internationalization with django
CRUD with Django
Authenticate Google with Django
Django 1.11 started with Python3.6
Upload files with Django
Development digest with Django
Output PDF with Django
Markdown output with Django
Use Gentelella with django
Twitter OAuth with Django
Send email with Django
File upload with django
Use LESS with Django
Pooling mechanize with Django
Use MySQL with Django
Start today with Django
Getting Started with Django 2
Get started with Django! ~ Tutorial ⑤ ~
Create an API with Django
Do Django with CodeStar (Python3.8, Django2.1.15)
Deploy Django serverless with Lambda
Python3 + Django ~ Mac ~ with Apache
How to check ORM behavior in one file with django
Getting Started with Python Django (1)
Create a homepage with django
Get started with Django! ~ Tutorial ④ ~
Getting Started with Python Django (4)
Web application creation with Django
Getting Started with Python Django (3)
Get started with Django! ~ Tutorial ⑥ ~
Save tweet data with Django
Do AES encryption with DJango
Getting Started with Python Django (6)
Getting Started with Django with PyCharm
Real-time web with Django Channels
Double submit suppression with Django
Django REST framework with Vue.js
Use prefetch_related conveniently with Django
Getting Started with Python Django (5)
Login with django rest framework
Qiita API Oauth with Django
Test Driven Development with Django Part 3
Build FastAPI + uvicorn + nginx with docker-compose
reload in django shell with ipython
Steps to develop Django with VSCode
Test Driven Development with Django Part 4
Load Django modules with an interpreter
Set up social login with Django
Test Driven Development with Django Part 6
Manage Django config files with Python-decouple
Deploy a Django application with Docker
Common html to rent with Django
Django Model with left outer join
Test Driven Development with Django Part 2
Django Tips-Create a ranking site with Django-
Twitter posting application made with Django
Automatically generate model relationships with Django
How to get started with Django
Run python3 Django1.9 with mod_wsgi (deploy)