Introduction 😉
I'm Manato Kato, Japanese college student, and I love Python.
I'd like to introduce my new project "FastAPI with Django ORM and Admin".
Beginning 📍
Programming is a means to an end
The reason why I do programming is because I want to create something and give it shape. Therefore, I see programming as just a means to an end.
The first technology I learned
My first programming language was Python, and I've been doing contests and internships in Python ever since. And I often use Django when writing server-side code. This is because Django was the first framework I ever touched, and I used Django+DRF in my internship.
Disadvantages of Django
However, Django has some disadvantages.
- Not very good for API development
- DRF is a must
- Tends to be complex and verbose even with DRF
- slow.
Looking for a new framework
So I decided to touch a new framework.
As mentioned above, I did not want to learn a new language because what I want to do is create things and programming is just a means to an end. (I was trying to get introduced to the Go language at one point, but gave it up due to lack of time).
After much research, I learned that a framework called FastAPI was coming along quite well.
Advantages of FastAPI
When I touched FastAPI, it was a revolution.
- I can include typedefs in Python.
- I was very happy to see this feature, as I had a hard time with DX dropping due to the lack of types in Django development at my internship.
- Ability to output API documentation by default.
- Genius.
- It's very effective in the division of labor with the frontend.
- fast.
Disadvantages of FastAPI
There are a lot of advantages as mentioned above, but I still miss Django.
-
Admin Page.
- This is still where the beauty of Django lies!
- I really want it.
- ORM
- My hands have grown comfortable with Django's ORM.
Then...
Let's merge FastAPI and Django!!!
Code 👨🏻💻
https://github.com/kathmandu777/fastapi-django-template
Directory structure
├── README.md
├── docker-compose.yml
├── fastapi
│ ├── Dockerfile
│ ├── app
│ │ ├── __init__.py
│ │ ├── admin
│ │ │ ├── __init__.py
│ │ │ └── user.py
│ │ ├── api
│ │ │ ├── __init__.py
│ │ │ ├── auth.py
│ │ │ └── user.py
│ │ ├── apps.py
│ │ ├── dependencies
│ │ │ ├── __init__.py
│ │ │ └── auth.py
│ │ ├── migrations
│ │ │ ├── 0001_initial.py
│ │ │ └── __init__.py
│ │ ├── models
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ └── user.py
│ │ ├── routers
│ │ │ ├── __init__.py
│ │ │ ├── auth.py
│ │ │ ├── health.py
│ │ │ └── user.py
│ │ └── schemas
│ │ ├── __init__.py
│ │ ├── auth.py
│ │ └── user.py
│ ├── config
│ │ ├── __init__.py
│ │ ├── asgi.py
│ │ ├── exceptions.py
│ │ ├── jwt.py
│ │ ├── log.py
│ │ ├── password.py
│ │ ├── settings
│ │ │ ├── base.py
│ │ │ ├── local.py
│ │ │ └── production.py
│ │ └── urls.py
│ ├── fastapi.env
│ ├── manage.py
│ ├── media
│ ├── poetry.lock
│ ├── pyproject.toml
│ ├── scripts
│ │ ├── runlocalserver.sh
│ │ └── startserver.sh
│ └── static
│ └── admin
├── poetry.lock
└── pyproject.toml
I use Django as a reference, and use a separate style for each application.
-
models
: Django ORM -
routers
: FastAPI routers -
schemas
: FastAPI Pydantic models -
api
: FastAPI view
mounts
"""
Django settings
"""
django_app = get_asgi_application()
"""
FastAPI settings
"""
from app.routers import auth_router, health_router, user_router
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
fastapi_app = FastAPI()
# routers
fastapi_app.include_router(health_router, tags=["health"], prefix="/health")
# to mount Django
fastapi_app.mount("/django", django_app)
fastapi_app.mount("/static", StaticFiles(directory="static"), name="static")
fastapi_app.mount("/media", StaticFiles(directory="media"), name="media")
Create an asgi application for Django and FastAPI, and mount the Django application from the FastAPI application.
Models
Same as when creating in Django.
class User(AbstractBaseUser, PermissionsMixin, BaseModelMixin):
objects = UserManager()
email = models.EmailField(_("email address"), unique=True)
MIN_LENGTH_USERNAME = 1
MAX_LENGTH_USERNAME = 20
username = models.CharField(
_("username"),
max_length=MAX_LENGTH_USERNAME,
)
# permissions
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
...
Schemas
from uuid import UUID
from pydantic import BaseModel
class ReadUserSchema(BaseModel):
uuid: UUID
username: str
email: str
class Config:
orm_mode = True
class CreateUserSchema(BaseModel):
username: str
email: str
password: str
orm_mode = True
is important.
Routers
Same as when creating in FastAPI.
user_router = APIRouter()
@user_router.get("/", response_model=ReadUserSchema)
async def get(request: Request, current_user: User = Depends(get_current_user)) -> User:
return UserAPI.get(request, current_user)
@user_router.post(
"/",
response_model=ReadUserSchema,
)
async def create(request: Request, schema: CreateUserSchema) -> User:
return await UserAPI.create(request, schema)
API
class UserAPI:
@classmethod
def get(cls, request: Request, current_user: User) -> User:
return current_user
@classmethod
async def create(cls, request: Request, schema: CreateUserSchema) -> User:
user = await User.objects.filter(email=schema.email).afirst()
if user:
raise HTTPException(status_code=400, detail="Email already registered")
schema.password = hash_password(schema.password)
return await sync_to_async(User.objects.create)(**schema.dict())
It is important to apply asynchronous processing to the DB using sync_to_async
, afirst
, etc. Synchronous processing will be very slow.
Asynchronous Processing in Django 4.1 🐍
Django 4.1 has been updated to allow asynchronous processing in the ORM, so you can now develop with a combination of FastAPI and Django like this. All of the reference articles below do not do asynchronous processing, so I expect them to be quite slow.
Finally 🏁
I am happy to build my ideal style. Since it is in the template repository, I hope you will use it.
As I am new to FastAPI, I am sure there are some weird things I am doing. Please send me Issue, PR.
References 📚
Using FastAPI with Django - Stavros' Stuff
https://www.stavros.io/posts/fastapi-with-django
https://qiita.com/Ningensei848/items/ac72ff6edf4d887cdcc1
My encounter with this article was the beginning of this project.
The integration of FastAPI and Django ORM
https://kigawas.me/posts/integrate-fastapi-and-django-orm/
https://github.com/kigawas/fastapi-django
Most helpful.
Learn to Use Django with FastAPI Frameworks
https://nsikakimoh.com/learn/django-and-fastapi-combo-tutorials
I found it while writing this article.
I think it differs from this project in that it uses wsgi to run Django and does not support async for the Django ORM.
Top comments (1)
Thank you, it was usper useful.
I really like your repo and stole some of your precommit config :D