← Back to Blog

Django vs Flask: A Comprehensive Tutorial

Learn the fundamentals of two popular Python web frameworks

Beginner Friendly

Python has become one of the most popular programming languages for web development, largely due to its simplicity, readability, and the powerful frameworks it offers. Two of the most widely used Python web frameworks are Django and Flask. In this tutorial, we'll explore both frameworks, understand their strengths and weaknesses, and learn how to build basic web applications with each.

Introduction to Web Frameworks

Web frameworks provide a structured way to build and deploy web applications. They handle many of the common tasks and challenges in web development, allowing developers to focus on building the unique features of their applications rather than reinventing the wheel.

Python web frameworks typically provide tools and libraries for:

  • URL routing (mapping URLs to code)
  • HTML templating (generating HTML dynamically)
  • Database access and ORM (Object-Relational Mapping)
  • Session management and user authentication
  • Security features (protection against common vulnerabilities)
  • Form handling and validation

Django and Flask represent two different philosophies in the world of web frameworks:

Django

A "batteries-included" framework that provides almost everything you need out of the box.

  • Full-featured and opinionated
  • Built-in admin interface
  • Integrated ORM
  • Authentication system
  • Form handling

Flask

A microframework that provides the essentials while keeping the core simple and extensible.

  • Lightweight and flexible
  • Minimal core functionality
  • Extensible through add-ons
  • Less opinionated
  • More control over components
Note: Both frameworks are excellent choices for web development. The "right" choice depends on your project requirements, team preferences, and development philosophy.

Django: The Batteries-Included Framework

Overview & Features

Django was created in 2003 and released publicly in 2005. It was designed with news websites in mind, which typically need to be built quickly, securely, and with the ability to handle high traffic.

Django follows the "batteries-included" philosophy, providing a comprehensive set of tools and features out of the box:

  • ORM (Object-Relational Mapper): Interact with your database using Python objects instead of SQL
  • Admin Interface: A ready-to-use interface for managing your site's content
  • Authentication System: User accounts, groups, permissions, and cookie-based sessions
  • Caching Framework: Hook into memcached or other caching systems
  • Form Handling: Define forms, validate input, and process submissions
  • Testing Framework: Tools for writing and running tests
  • Internationalization: Support for multiple languages and time zones

Installation & Setup

Let's start by installing Django. It's recommended to use a virtual environment to keep your project dependencies isolated.

# Create a virtual environment
python -m venv django_env

# Activate the virtual environment
# On Windows:
django_env\Scripts\activate
# On macOS/Linux:
source django_env/bin/activate

# Install Django
pip install django

# Verify installation
python -m django --version
Tip: Always use virtual environments for your Python projects to avoid dependency conflicts between different projects.

Creating Your First Django Project

Once Django is installed, you can create a new project:

# Create a new Django project
django-admin startproject mysite

# Navigate to the project directory
cd mysite

# Run the development server
python manage.py runserver

Now you can visit http://127.0.0.1:8000/ in your browser to see your new Django project in action!

Let's understand the project structure:

mysite/
    manage.py            # Command-line utility for administrative tasks
    mysite/              # Project package
        __init__.py      # Empty file that tells Python this is a package
        settings.py      # Project settings/configuration
        urls.py          # URL declarations for the project
        asgi.py          # Entry point for ASGI-compatible web servers
        wsgi.py          # Entry point for WSGI-compatible web servers

Now, let's create an app within our project. In Django, a project can contain multiple apps, and each app serves a specific purpose:

# Create a new app
python manage.py startapp polls

This creates a new directory with the following structure:

polls/
    __init__.py          # Empty file that tells Python this is a package
    admin.py             # Register models with the admin interface
    apps.py              # App configuration
    migrations/          # Database migrations
        __init__.py
    models.py            # Data models
    tests.py             # Test cases
    views.py             # View functions

Working with Models & Databases

Django's ORM allows you to define your data models as Python classes. Let's create a simple model for a poll application:

# polls/models.py
from django.db import models

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def __str__(self):
        return self.question_text

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self):
        return self.choice_text

After defining your models, you need to:

  1. Add your app to INSTALLED_APPS in settings.py
  2. Create migrations
  3. Apply migrations to create the database tables
# Add 'polls' to INSTALLED_APPS in mysite/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'polls',  # Add this line
]

# Create migrations
python manage.py makemigrations polls

# Apply migrations
python manage.py migrate

Views & Templates

Views in Django handle the logic for processing requests and returning responses. Let's create a simple view to display a list of questions:

# polls/views.py
from django.shortcuts import render
from .models import Question

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    context = {'latest_question_list': latest_question_list}
    return render(request, 'polls/index.html', context)

Now, we need to create a template to render the data:

# Create directory: polls/templates/polls/
# Create file: polls/templates/polls/index.html

{% if latest_question_list %}
    <ul>
    {% for question in latest_question_list %}
        <li>{{ question.question_text }}</li>
    {% endfor %}
    </ul>
{% else %}
    <p>No polls are available.</p>
{% endif %}

Finally, we need to map a URL to our view:

# Create file: polls/urls.py
from django.urls import path
from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.index, name='index'),
]

# Update mysite/urls.py
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('admin/', admin.site.urls),
    path('polls/', include('polls.urls')),
]

The Admin Interface

One of Django's most powerful features is its automatic admin interface. To use it, you need to:

  1. Create a superuser
  2. Register your models with the admin site
# Create a superuser
python manage.py createsuperuser

# Register models in polls/admin.py
from django.contrib import admin
from .models import Question, Choice

admin.site.register(Question)
admin.site.register(Choice)

Now you can visit http://127.0.0.1:8000/admin/ and log in with your superuser credentials to manage your site's content.

Tip: Django's admin interface is highly customizable. You can create custom admin classes to control how your models are displayed and edited.

Flask: The Microframework

Overview & Features

Flask was created in 2010 as a lightweight alternative to more comprehensive frameworks. It's designed to be simple, flexible, and easy to extend.

Flask follows the "microframework" philosophy, providing a minimal core with the ability to add extensions as needed:

  • Routing: Map URLs to Python functions
  • Templating: Jinja2 templating engine
  • Development Server: Built-in server for development
  • Debugger: Interactive debugger for development
  • RESTful Request Handling: Access request data easily
  • Unit Testing Support: Built on Werkzeug and unittest

Everything else (database access, form validation, authentication, etc.) is provided through extensions or can be implemented by the developer.

Installation & Setup

Let's start by installing Flask. As with Django, it's recommended to use a virtual environment:

# Create a virtual environment
python -m venv flask_env

# Activate the virtual environment
# On Windows:
flask_env\Scripts\activate
# On macOS/Linux:
source flask_env/bin/activate

# Install Flask
pip install flask

# Verify installation
python -c "import flask; print(flask.__version__)"

Creating Your First Flask Application

Creating a Flask application is remarkably simple. Here's a minimal example:

# app.py
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

if __name__ == '__main__':
    app.run(debug=True)

Run this script with python app.py, and you'll have a web server running at http://127.0.0.1:5000/.

For larger applications, you might want to use a more structured approach. Here's a common project structure for Flask applications:

myflaskapp/
    app/
        __init__.py      # Initialize the Flask application
        views/           # View functions
        models/          # Data models
        templates/       # Jinja2 templates
        static/          # Static files (CSS, JS, images)
    config.py            # Configuration settings
    requirements.txt     # Dependencies
    run.py               # Script to run the application

Routing & Views

Flask uses decorators to define routes. Here's how you can define multiple routes:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'Index Page'

@app.route('/hello')
def hello():
    return 'Hello, World!'

@app.route('/user/<username>')
def show_user_profile(username):
    return f'User {username}'

@app.route('/post/<int:post_id>')
def show_post(post_id):
    return f'Post {post_id}'

Flask supports variable rules in URLs, as shown in the /user/<username> and /post/<int:post_id> examples. You can also specify the HTTP methods that a route should respond to:

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        # Process the login form
        return 'Processing login'
    else:
        # Show the login form
        return 'Please log in'

Templates & Static Files

Flask uses Jinja2 for templating. Templates are stored in the templates directory, and static files (CSS, JavaScript, images) are stored in the static directory.


# app.py
from flask import Flask, render_template

app = Flask(__name__)

@app.route('/hello/<name>')
def hello(name=None):
    return render_template('hello.html', name=name)
<!-- templates/hello.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Hello from Flask</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <h1>Hello, {{ name }}!</h1>
</body>
</html>
                

Jinja2 templates support variables, filters, control structures, and template inheritance, making it easy to create complex layouts with reusable components.

Working with Extensions

Flask's power comes from its extensibility. There are extensions for almost everything you might need:

  • Flask-SQLAlchemy: ORM for database access
  • Flask-WTF: Form handling and validation
  • Flask-Login: User authentication
  • Flask-RESTful: Building REST APIs
  • Flask-Migrate: Database migrations
  • Flask-Admin: Admin interface

Let's see how to use Flask-SQLAlchemy for database access:

# Install Flask-SQLAlchemy
pip install flask-sqlalchemy

# app.py
from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todos.db'
db = SQLAlchemy(app)

class Todo(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    content = db.Column(db.String(200), nullable=False)

    def __repr__(self):
        return f'<Todo {self.id}>'

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        todo_content = request.form['content']
        new_todo = Todo(content=todo_content)

        try:
            db.session.add(new_todo)
            db.session.commit()
            return redirect('/')
        except:
            return 'There was an issue adding your todo'
    else:
        todos = Todo.query.all()
        return render_template('index.html', todos=todos)

if __name__ == '__main__':
    with app.app_context():
        db.create_all()
    app.run(debug=True)
Note: Flask extensions typically follow a similar pattern: import the extension, initialize it with your Flask app, and then use its features.

Django vs Flask: A Detailed Comparison

Now that we've explored both frameworks, let's compare them across various dimensions:

Feature Django Flask
Philosophy Batteries-included, opinionated Microframework, flexible
Learning Curve Steeper (more concepts to learn) Gentler (simpler core)
Project Structure Enforced, consistent Flexible, up to the developer
Database Built-in ORM Extensions (e.g., SQLAlchemy)
Admin Interface Built-in, powerful Extensions (e.g., Flask-Admin)
Authentication Built-in Extensions (e.g., Flask-Login)
Forms Built-in Extensions (e.g., Flask-WTF)
Templating Django Templates Jinja2 (similar but more powerful)
Routing URL patterns in urls.py Decorators on view functions
Development Speed Faster for standard features Faster for custom, unique features
Flexibility Less flexible (follows Django's way) More flexible (build it your way)
Community & Ecosystem Larger, more established Growing rapidly

When to Use Each Framework

When to Use Django

  • Building content-heavy sites (blogs, news sites)
  • Projects with standard features (user accounts, admin panels)
  • When you need to move quickly with a full-featured site
  • Large, complex applications with many components
  • Teams that benefit from enforced structure
  • Projects where security is a top priority

When to Use Flask

  • Building small to medium-sized applications
  • Projects with unique, non-standard requirements
  • When you need fine-grained control over components
  • API services and microservices
  • Prototyping and experimentation
  • Learning web development concepts
Warning: Don't choose a framework based solely on its popularity or what others are using. Consider your project's specific needs, your team's expertise, and your development philosophy.

Conclusion & Next Steps

Both Django and Flask are excellent frameworks with their own strengths and ideal use cases. Django provides a comprehensive, integrated solution that's perfect for building full-featured websites quickly. Flask offers a lightweight, flexible foundation that's ideal for custom applications and APIs.

The best way to decide which framework is right for you is to try both and see which aligns better with your thinking and project needs.

Next Steps for Learning Django:

  1. Complete the official Django Tutorial
  2. Explore Django's documentation for deeper understanding
  3. Build a simple CRUD application
  4. Learn about Django REST framework for building APIs
  5. Explore Django's deployment options

Next Steps for Learning Flask:

  1. Complete the official Flask Tutorial
  2. Explore popular Flask extensions
  3. Build a RESTful API
  4. Learn about application factories and blueprints for larger applications
  5. Explore Flask's deployment options
Tip: The best way to learn is by doing. Start with a small project and gradually add features as you learn more about the framework.

Remember, the goal is not to find the "best" framework, but the one that's best for your specific needs and preferences. Happy coding!

Wesley Classen
Wesley's AI Assistant Usually replies in ~15 min Ask me anything — if I can't answer, Wesley gets pinged and replies personally.
Hello! I'm Wesley's AI assistant. How can I help you today?