In recent years, a real revolution has been taking place in the world of Python development. More and more teams are choosing FastAPI for new projects, gradually pushing aside Django, a framework that has been the industry standard for many years. Let's figure out what's going on and why beginner developers should pay attention to FastAPI.
What is FastAPI and Django?
Django is a full-featured web framework that has existed since 2005. It was created to develop full-fledged web applications with a built-in admin panel, ORM, template system and many other "out of the box" features.
FastAPI — a modern framework that appeared in 2018, specially created for API development. It is built on the modern capabilities of Python 3.7+ and asynchronous programming.
Why is FastAPI gaining popularity?
1. Performance like Go and Node.js
FastAPI is one of the fastest Python frameworks thanks to its asynchrony. Here's a simple comparison:
# Django (synchronous approach)
from django.http import JsonResponse
def get_users(request):
users = User.objects.all() # Blocking request
return JsonResponse({'users': list(users.values())})# FastAPI (asynchronous approach)
from fastapi import FastAPI
from typing import List
app = FastAPI()
@app.get("/users")
async def get_users() -> List[dict]:
users = await database.fetch_all("SELECT * FROM users")
return users💡 Important: In FastAPI, requests are processed asynchronously, which allows the server to serve thousands of connections simultaneously without blocking. Django also supports asynchrony since version 3.1, but the ecosystem is not yet fully adapted.
2. Incredibly easy start
You can create your first API in FastAPI in just 5 minutes:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello, world!"}
@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}Run with the command:
uvicorn main:app --reload✅ And that's it! You already have a working API. No settings, configuration files, or complex project structures.
3. Automatic documentation is magic
One of the coolest features of FastAPI is automatic interactive documentation. Just open http://localhost:8000/docs, and you will see the complete Swagger UI documentation, where you can test each endpoint directly in the browser.
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI(
title="My project's API",
description="Description of all endpoints",
version="1.0.0"
)
class Item(BaseModel):
name: str
description: str = None
price: float
@app.post("/items/")
async def create_item(item: Item):
"""
Creating a new product:
- **name**: product name
- **description**: description (optional)
- **price**: product price
"""
return {"item": item}Documentation is generated automatically from data types and docstrings. In Django, you need to use additional libraries like drf-spectacular for this.
4. Standardization and validation out of the box
FastAPI uses Pydantic for automatic data validation:
from pydantic import BaseModel, EmailStr, validator
from typing import Optional
class User(BaseModel):
username: str
email: EmailStr
age: Optional[int] = None
@validator('age')
def age_must_be_positive(cls, v):
if v is not None and v < 0:
raise ValueError('Age cannot be negative')
return v
@app.post("/users/")
async def create_user(user: User):
# If the data is not valid, FastAPI will automatically return a 422 error
# with a detailed description of the problem
return {"user": user}If you send invalid data, you will receive a clear error indicating all the problems.
5. Modern work with dependencies
Dependency Injection in FastAPI makes the code clean and testable:
from fastapi import Depends, HTTPException
from sqlalchemy.orm import Session
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
def get_current_user(token: str = Header(...)):
user = verify_token(token)
if not user:
raise HTTPException(status_code=401, detail="Unauthorized")
return user
@app.get("/users/me")
async def read_current_user(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
return current_userDependencies are automatically resolved and implemented. This makes testing incredibly easy.
6. WebSocket and background tasks
from fastapi import WebSocket, BackgroundTasks
import time
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Received: {data}")
def write_log(message: str):
time.sleep(5) # Long operation
with open("log.txt", "a") as f:
f.write(message)
@app.post("/send-notification/")
async def send_notification(
email: str,
background_tasks: BackgroundTasks
):
background_tasks.add_task(write_log, f"Sent to {email}")
return {"message": "Notification will be sent"}
When to choose Django?
FastAPI is not always the best choice. Django is preferable if you need:
Full-fledged web application with admin panel — Django Admin out of the box
Authentication and authorization system - ready and time-tested
ORM with migrations — Django ORM is easier for beginners
Built-in template system — if you need server-side rendering
Huge ecosystem of packages — Django has been around for 19 years
Practical example: CRUD API
Let's create a simple CRUD API for managing tasks:
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional
from datetime import datetime
app = FastAPI()
class Task(BaseModel):
id: Optional[int] = None
title: str
description: Optional[str] = None
completed: bool = False
created_at: Optional[datetime] = None
# Temporary storage (in reality, use a database)
tasks_db = []
task_id_counter = 1
@app.post("/tasks/", response_model=Task)
async def create_task(task: Task):
global task_id_counter
task.id = task_id_counter
task.created_at = datetime.now()
task_id_counter += 1
tasks_db.append(task)
return task
@app.get("/tasks/", response_model=List[Task])
async def get_tasks(completed: Optional[bool] = None):
if completed is None:
return tasks_db
return [t for t in tasks_db if t.completed == completed]
@app.get("/tasks/{task_id}", response_model=Task)
async def get_task(task_id: int):
task = next((t for t in tasks_db if t.id == task_id), None)
if not task:
raise HTTPException(status_code=404, detail="Task not found")
return task
@app.put("/tasks/{task_id}", response_model=Task)
async def update_task(task_id: int, task_update: Task):
task = next((t for t in tasks_db if t.id == task_id), None)
if not task:
raise HTTPException(status_code=404, detail="Task not found")
task.title = task_update.title
task.description = task_update.description
task.completed = task_update.completed
return task
@app.delete("/tasks/{task_id}")
async def delete_task(task_id: int):
global tasks_db
tasks_db = [t for t in tasks_db if t.id != task_id]
return {"message": "Task deleted"}Database integration
FastAPI works great with SQLAlchemy:
from sqlalchemy import create_engine, Column, Integer, String, Boolean
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "sqlite:///./tasks.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
class TaskModel(Base):
__tablename__ = "tasks"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
description = Column(String)
completed = Column(Boolean, default=False)
Base.metadata.create_all(bind=engine)
@app.post("/tasks/", response_model=Task)
async def create_task(task: Task, db: Session = Depends(get_db)):
db_task = TaskModel(**task.dict(exclude={'id'}))
db.add(db_task)
db.commit()
db.refresh(db_task)
return db_taskAuthentication and security
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from passlib.context import CryptContext
from jose import JWTError, jwt
from datetime import datetime, timedelta
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
def create_access_token(data: dict):
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(minutes=30)
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(form_data.username, form_data.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid credentials"
)
access_token = create_access_token(data={"sub": user.username})
return {"access_token": access_token, "token_type": "bearer"}
async def get_current_user(token: str = Depends(oauth2_scheme)):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise HTTPException(status_code=401)
return username
except JWTError:
raise HTTPException(status_code=401)
@app.get("/users/me")
async def read_users_me(current_user: str = Depends(get_current_user)):
return {"username": current_user}Testing
FastAPI makes testing easy:
from fastapi.testclient import TestClient
client = TestClient(app)
def test_create_task():
response = client.post(
"/tasks/",
json={"title": "Test task", "description": "Description"}
)
assert response.status_code == 200
assert response.json()["title"] == "Test task"
def test_get_tasks():
response = client.get("/tasks/")
assert response.status_code == 200
assert isinstance(response.json(), list)Performance: facts and figures
According to TechEmpower Benchmarks (2026):
Framework | Requests per second | Performance |
|---|---|---|
FastAPI | ~60,000 | ⭐⭐⭐⭐⭐ |
Django Ninja | ~40,000 | ⭐⭐⭐⭐ |
Django + gunicorn | ~10,000 | ⭐⭐⭐ |
🚀 Conclusion: FastAPI can handle 6 times more requests with the same load!
In Codice you will find detailed courses on Python, FastAPI, Django and other modern technologies. We teach programming in practice — with real projects and clear explanations.
🚀 Join our Telegram channel - here you will find a friendly community of developers, useful materials, code analysis and answers to questions. We will help you become a sought-after specialist!
Start your programming journey with Kodika — learn conveniently, quickly and efficiently!
