programming

The different between Django, Flask, and FastAPI

oleh Ekky Armandi • 16 Agu 2024

![[images/introduction-to-fastapi/Pasted image 20240816183405.png|Thumbnail of The different between Django, Flask, and FastAPI]]

Hi, it’s Ekky. I’m a freelance developer with experience in web development and web scraping. I am also known as a Python Developer. I greatly use Python in my work, from simple scripts to full-stack applications. You also can find my portfolio website here.

In this article, I want to introduce you to FastAPI, a Python library you can use to build an API. And then, I compared it to other Python libraries like Django and Flask in terms of speed.

What is API?

If you are new to programming and have no clue what API is.

API is a short-term for Application Programming Interface. It’s a server-side application and is mostly used for data transactions on the client side like desktop apps, mobile apps, and also web apps simultanously.

![[images/introduction-to-fastapi/Pasted image 20240816134309.png|source: https://elancer.co.kr]]

You just have to build it once and use it on the other app.

What is FastAPI?

FastAPI is a modern and fast web framework for building APIs in Python, designed with simplicity, flexibility, and performance in mind. Maintained by Sebastián Ramírez known as @tiangolo

The first time I discovered it, I was surprised at how easy to get FastAPI running on my local machine. What you have to do is just:

  • Install the FastAPI library
    pip install fastapi uvicorn
  • Write the code below
    from fastapi import FastAPI  
      
    app = FastAPI()  
      
      
    @app.get("/")  
    def read_root():  
    return {"Hello": "World"}
  • Then run the code using uvicorn from your terminal
    uvicorn main:app --reload

It will output something like this:

INFO: Will watch for changes in these directories: ['/your-app-path']  
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)  
INFO: Started reloader process [31469] using StatReload  
INFO: Started server process [31471]  
INFO: Waiting for application startup.  
INFO: Application startup complete.

Visit the website on http://localhost:8000 or http://localhost:8000/docs for the swagger version

Comparing FastAPI to Django and Flask

As a comparison to the other Python API frameworks, I will show how API is built on Django, Flask, and FastAPI. The app it self is about library inventory management.

Django Rest Framework

Let’s assume we’re creating a simple API for a book library.

  1. Set up the Django project
  2. Install Django Rest Framework
    pip install django djangorestframework
  3. Configure DRF in your project settings.py:
    INSTALLED_APPS = [  
    	# ...  
    	'rest_framework',  
    	'your_app_name',  
    ]
  4. Create a model in your_app/models.py:
    from django.db import models  
      
    class Book(models.Model):  
    	title = models.CharField(max_length=100)  
    	author = models.CharField(max_length=100)  
    	publication_date = models.DateField()  
      
    def __str__(self):  
    	return self.title
  5. Create a serializer in your_app/serializers.py:
    from rest_framework import serializers  
    from .models import Book  
      
    class BookSerializer(serializers.ModelSerializer):  
    class Meta:  
    	model = Book  
    	fields = ['id', 'title', 'author', 'publication_date']
  6. Define views in your_app/views.py:
    from rest_framework import viewsets  
    from .models import Book  
    from .serializers import BookSerializer  
      
    class BookViewSet(viewsets.ModelViewSet):  
    	queryset = Book.objects.all()  
    	serializer_class = BookSerializer
  7. Setup URL routing in your_project/urls.py:
    from django.contrib import admin  
    from django.urls import path, include  
    from rest_framework.routers import DefaultRouter  
    from your_app.views import BookViewSet  
      
    router = DefaultRouter()  
    router.register(r'books', BookViewSet)  
      
    urlpatterns = [  
    	path('admin/', admin.site.urls),  
    	path('api/', include(router.urls)),
    ]
  8. Run the migrations
    python manage.py makemigrations  
    python manage.py migrate
  9. Run the server
    python manage.py runserver

This setup creates a full CRUD API for the Book model. You can now:

  • List all books: GET /api/books/
  • Create a new book: POST /api/books/
  • Retrieve a specific book: GET /api/books/{id}/
  • Update a book: PUT /api/books/{id}/
  • Delete a book: DELETE /api/books/{id}/

Flask

Building an API using Flask is quite straightforward compared to Django. I’ll provide a similar example to the Django one, creating a simple API for a book library. Here’s how you can build an API using Flask:

  1. Install required packages
    pip install flask flask-sqlalchemy flask-marshmallow marshmallow-sqlalchemy
  2. Create app.py
    from flask import Flask, request, jsonify  
    from flask_sqlalchemy import SQLAlchemy  
    from flask_marshmallow import Marshmallow  
    from marshmallow import fields  
    import os  
      
    # Initialize app  
    app = Flask(__name__)  
    basedir = os.path.abspath(os.path.dirname(__file__))  
      
    # Database  
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'db.sqlite')  
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False  
      
    # Initialize db  
    db = SQLAlchemy(app)  
      
    # Initialize ma  
    ma = Marshmallow(app)  
      
    # Book Model  
    class Book(db.Model):  
    id = db.Column(db.Integer, primary_key=True)  
    title = db.Column(db.String(100), unique=True)  
    author = db.Column(db.String(100))  
    publication_date = db.Column(db.Date)  
      
    def __init__(self, title, author, publication_date):  
    self.title = title  
    self.author = author  
    self.publication_date = publication_date  
      
    # Book Schema  
    class BookSchema(ma.Schema):  
    class Meta:  
    fields = ('id', 'title', 'author', 'publication_date')  
      
    # Initialize schema  
    book_schema = BookSchema()  
    books_schema = BookSchema(many=True)  
      
    # Create a book  
    @app.route('/book', methods=['POST'])  
    def add_book():  
    title = request.json['title']  
    author = request.json['author']  
    publication_date = request.json['publication_date']  
      
    new_book = Book(title, author, publication_date)  
      
    db.session.add(new_book)  
    db.session.commit()  
      
    return book_schema.jsonify(new_book)  
      
    # Get all books  
    @app.route('/book', methods=['GET'])  
    def get_books():  
    all_books = Book.query.all()  
    result = books_schema.dump(all_books)  
    return jsonify(result)  
      
    # Get single book  
    @app.route('/book/<id>', methods=['GET'])  
    def get_book(id):  
    book = Book.query.get(id)  
    return book_schema.jsonify(book)  
      
    # Update a book  
    @app.route('/book/<id>', methods=['PUT'])  
    def update_book(id):  
    book = Book.query.get(id)  
      
    title = request.json['title']  
    author = request.json['author']  
    publication_date = request.json['publication_date']  
      
    book.title = title  
    book.author = author  
    book.publication_date = publication_date  
      
    db.session.commit()  
      
    return book_schema.jsonify(book)  
      
    # Delete book  
    @app.route('/book/<id>', methods=['DELETE'])  
    def delete_book(id):  
    book = Book.query.get(id)  
    db.session.delete(book)  
    db.session.commit()  
      
    return book_schema.jsonify(book)  
      
    # Run server  
    if __name__ == '__main__':  
    app.run(debug=True)
  3. Create the database
    from app import db  
    db.create_all()
  4. Run the application
    python app.py

This Flask app provides similar functionality to the Django example:

  • Create a book: POST /book
  • Get all books: GET /book
  • Get a specific book: GET /book/
  • Update a book: PUT /book/
  • Delete a book: DELETE /book/

The main differences are:

  1. Flask is more lightweight and requires less boilerplate code.
  2. You need to explicitly define routes for each operation.
  3. SQLAlchemy is used for database operations instead of Django’s ORM.
  4. Marshmallow is used for serialization instead of Django REST Framework’s serializers.

FastAPI

Here’s how you can implement the same functionality in FastAPI:

  1. First, install the required packages:
    pip install fastapi uvicorn sqlalchemy pydantic
  2. Create main.py
    from fastapi import FastAPI, HTTPException, Depends
    from sqlalchemy import create_engine, Column, Integer, String, Date
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy.orm import sessionmaker, Session
    from pydantic import BaseModel
    from datetime import date
    from typing import List
    
    # Database setup
    SQLALCHEMY_DATABASE_URL = "sqlite:///./books.db"
    engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
    SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
    Base = declarative_base()
    
    # Database model
    class BookDB(Base):
        __tablename__ = "books"
    
        id = Column(Integer, primary_key=True, index=True)
        title = Column(String, unique=True, index=True)
        author = Column(String, index=True)
        publication_date = Column(Date)
    
    # Pydantic models
    class BookBase(BaseModel):
        title: str
        author: str
        publication_date: date
    
    class BookCreate(BookBase):
        pass
    
    class Book(BookBase):
        id: int
    
        class Config:
            orm_mode = True
    
    # Create tables
    Base.metadata.create_all(bind=engine)
    
    # FastAPI app
    app = FastAPI()
    
    # Dependency
    def get_db():
        db = SessionLocal()
        try:
            yield db
        finally:
            db.close()
    
    # Create a book
    @app.post("/books/", response_model=Book)
    def create_book(book: BookCreate, db: Session = Depends(get_db)):
        db_book = BookDB(**book.dict())
        db.add(db_book)
        db.commit()
        db.refresh(db_book)
        return db_book
    
    # Get all books
    @app.get("/books/", response_model=List[Book])
    def read_books(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
        books = db.query(BookDB).offset(skip).limit(limit).all()
        return books
    
    # Get a specific book
    @app.get("/books/{book_id}", response_model=Book)
    def read_book(book_id: int, db: Session = Depends(get_db)):
        book = db.query(BookDB).filter(BookDB.id == book_id).first()
        if book is None:
            raise HTTPException(status_code=404, detail="Book not found")
        return book
    
    # Update a book
    @app.put("/books/{book_id}", response_model=Book)
    def update_book(book_id: int, book: BookCreate, db: Session = Depends(get_db)):
        db_book = db.query(BookDB).filter(BookDB.id == book_id).first()
        if db_book is None:
            raise HTTPException(status_code=404, detail="Book not found")
        for var, value in vars(book).items():
            setattr(db_book, var, value) if value else None
        db.add(db_book)
        db.commit()
        db.refresh(db_book)
        return db_book
    
    # Delete a book
    @app.delete("/books/{book_id}", response_model=Book)
    def delete_book(book_id: int, db: Session = Depends(get_db)):
        book = db.query(BookDB).filter(BookDB.id == book_id).first()
        if book is None:
            raise HTTPException(status_code=404, detail="Book not found")
        db.delete(book)
        db.commit()
        return book
    
    if __name__ == "__main__":
        import uvicorn
        uvicorn.run(app, host="0.0.0.0", port=8000)
  3. Run the application
    uvicorn main:app --reload

This FastAPI app provides the same functionality as the Django and Flask examples:

  • Create a book: POST /books/
  • Get all books: GET /books/
  • Get a specific book: GET /books/{book_id}
  • Update a book: PUT /books/{book_id}
  • Delete a book: DELETE /books/{book_id}

Key differences and advantages of FastAPI:

  1. FastAPI uses type hints for request and response models, providing automatic data validation.
  2. It generates OpenAPI (Swagger) documentation automatically, which you can view at http://localhost:8000/docs when running the app.
  3. It’s built on top of Starlette and Pydantic, offering high performance.
  4. It uses async/await syntax, though this example doesn’t showcase it for simplicity.
  5. Dependency injection is used for database sessions.

Conclusion

FastAPI is a modern and fast web framework for building APIs in Python, designed with simplicity, flexibility, and performance in mind. It offers several advantages over other Python web frameworks such as Django and Flask. Hence, it’s a fantastic choice for developers who want to create robust APIs quickly and easily.

This article also featured on Medium

Follow me on