A Comprehensive Guide to 100 Essential Django Libraries

By Bhargav Patoliya | Self-Researched Note

Table of Contents

APIs & Serialization

This category focuses on libraries that help you build and manage APIs (Application Programming Interfaces), which allow your Django application to communicate with other services, like a frontend JavaScript framework or a mobile app.

1. Django REST Framework (DRF)

What it is

DRF is the most popular and powerful toolkit for building Web APIs in Django. It provides a huge set of tools to make creating RESTful APIs incredibly efficient.

Why it's used

Building APIs from scratch in Django is tedious. You'd have to handle serializing querysets to JSON, deserializing incoming data, authenticating requests, managing permissions, and much more. DRF automates all of this with well-designed, reusable components.

Core Concepts

  • Serializers: Convert complex data types, like Django model instances, into native Python datatypes that can then be easily rendered into JSON, XML, or other content types. They also handle deserialization and validation.
  • ViewSets: A high-level abstraction that combines the logic for a set of related views (e.g., list, retrieve, create, update, delete) into a single class.
  • Routers: Automatically generate URL patterns for your ViewSets, saving you from writing them manually.

Simple Example

Let's create a simple API to list books.

# models.py
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=100)

# serializers.py
from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['id', 'title', 'author'] # Fields to include in the API output

# 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

# urls.py
from rest_framework.routers import DefaultRouter
from .views import BookViewSet

router = DefaultRouter()
router.register(r'books', BookViewSet, basename='book')
urlpatterns = router.urls

# After this setup, a GET request to /books/ will return a JSON list of all books.

2. DRF Simple JWT

What it is

A JSON Web Token (JWT) authentication plugin for DRF. JWTs are a modern, stateless way to handle user authentication in APIs.

Why it's used

Traditional session-based authentication doesn't work well for APIs, especially with separate frontend applications (SPAs) or mobile apps. JWTs provide a self-contained, secure token that the client can send with each request to prove who they are.

Core Concepts

  • Access Token: A short-lived token that the client sends in the Authorization header to access protected resources.
  • Refresh Token: A long-lived token used to get a new access token once the old one expires, without forcing the user to log in again.

Simple Example

Add JWT endpoints to your urls.py.

# settings.py
# Add DRF Simple JWT as the default authentication class
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
}

# urls.py
from django.urls import path
from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

urlpatterns = [
    # ... your other urls
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]

# Now, you can POST a username and password to /api/token/ to get an access and refresh token.
# To protect a view, add `permission_classes = [IsAuthenticated]` to it.

3. drf-spectacular

What it is

A library that automatically generates an OpenAPI 3 schema from your DRF API. OpenAPI (formerly Swagger) is a standard for documenting APIs.

Why it's used

Manually writing API documentation is time-consuming and prone to errors. drf-spectacular introspects your code (ViewSets, Serializers, etc.) to create accurate, up-to-date documentation automatically. It also provides beautiful interactive UI tools like Swagger UI and Redoc.

Core Concepts

  • Schema Generation: The process of inspecting code to build the API structure definition.
  • Swagger UI / Redoc: Interactive UIs that display your API documentation and allow developers to try out API endpoints directly from the browser.

Simple Example

# settings.py
INSTALLED_APPS = [
    # ...
    'drf_spectacular',
]

REST_FRAMEWORK = {
    # Tells DRF to use drf-spectacular for schema generation
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}

# urls.py
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView
from django.urls import path

urlpatterns = [
    # ... your API urls
    path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
    # Optional UI:
    path('api/schema/swagger-ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
    path('api/schema/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
]

# Visit /api/schema/swagger-ui/ to see your interactive API documentation.

4. Django Ninja

What it is

A fast, modern alternative to DRF for building APIs. It's heavily inspired by FastAPI.

Why it's used

It leverages Python's type hints and the Pydantic library for automatic data validation, serialization, and documentation. This can lead to cleaner, more explicit code and excellent performance. It's considered easier to learn for simple APIs than DRF.

Core Concepts

  • Pydantic Schemas: Instead of DRF Serializers, you define the shape of your data using Pydantic models with standard Python type hints.
  • Function-Based Views: API endpoints are often defined with simple functions decorated to handle HTTP methods.
  • Automatic Docs: Like drf-spectacular, it generates OpenAPI documentation automatically.

Simple Example

# api.py (a new file in your Django app)
from ninja import NinjaAPI, Schema
from typing import List

api = NinjaAPI()

# Define the data shape using Pydantic's Schema
class ItemSchema(Schema):
    id: int
    name: str
    description: str = None # Optional field

# A simple in-memory "database" for the example
items_db = {
    1: {"id": 1, "name": "Hammer", "description": "A good hammer"},
    2: {"id": 2, "name": "Screwdriver", "description": "A good screwdriver"},
}

# Define an endpoint using a decorator
@api.get("/items", response=List[ItemSchema])
def list_items(request):
    return list(items_db.values()) 

# project/urls.py
from django.urls import path
from myapp.api import api

urlpatterns = [
    # ...
    path("api/", api.urls),
]

# Visit /api/docs to see the automatically generated documentation.

5. Graphene-Django

What it is

The go-to library for integrating GraphQL into your Django project.

Why it's used

GraphQL is an alternative to REST. It allows the client to request exactly the data it needs and nothing more, which can be more efficient. Instead of multiple endpoints (like /users/1, /users/1/posts), you have a single endpoint that accepts complex queries.

Core Concepts

  • Schema: Defines the types of data available in your API (e.g., UserType, PostType).
  • Queries: Used to fetch data. The client specifies which fields they want.
  • Mutations: Used to create, update, or delete data.

Simple Example

# models.py
from django.db import models
class Ingredient(models.Model):
    name = models.CharField(max_length=100)

# schema.py (in your app)
import graphene
from graphene_django import DjangoObjectType
from .models import Ingredient

# Create a GraphQL type from your Django model
class IngredientType(DjangoObjectType):
    class Meta:
        model = Ingredient
        fields = ("id", "name")

# Define the root query
class Query(graphene.ObjectType):
    all_ingredients = graphene.List(IngredientType)

    def resolve_all_ingredients(root, info):
        # We can easily optimize query performance here
        return Ingredient.objects.all()

schema = graphene.Schema(query=Query) 

# urls.py
from django.urls import path
from graphene_django.views import GraphQLView
from myapp.schema import schema

urlpatterns = [
    # ...
    path("graphql", GraphQLView.as_view(graphiql=True, schema=schema)),
]
# You can now send GraphQL queries to the /graphql endpoint.

6. Djoser

What it is

A library that provides a set of DRF views to handle basic authentication tasks like registration, login, logout, password reset, and account activation.

Why it's used

It provides ready-to-use endpoints for common user management actions. Instead of writing these views yourself, you just include Djoser's URLs, and you're done. It saves a lot of boilerplate code.

Core Concepts

It's essentially a pre-packaged set of DRF views and serializers mapped to URLs for user management.

Simple Example

# settings.py
INSTALLED_APPS = [
    # ...
    'rest_framework',
    'djoser',
]

# urls.py
from django.urls import path, include

urlpatterns = [
    # ...
    path('auth/', include('djoser.urls')),
    # If using JWT, include these URLs as well
    path('auth/', include('djoser.urls.jwt')),
]

# This instantly gives you endpoints like:
# /auth/users/ (for registration)
# /auth/jwt/create/ (for login)
# /auth/users/me/ (to get current user details)
# ...and many more.

7. dj-rest-auth

What it is

A comprehensive API authentication solution for DRF. It's the spiritual successor to the unmaintained django-rest-auth.

Why it's used

While Djoser is great, dj-rest-auth offers more features out of the box, especially seamless integration with django-allauth for social authentication (login with Google, Facebook, etc.) via your API.

Core Concepts

Like Djoser, it provides pre-built endpoints. Its key advantage is the deep integration with django-allauth.

Simple Example

# settings.py
INSTALLED_APPS = [
    # ...
    'rest_framework',
    'rest_framework.authtoken',
    'dj_rest_auth',
    'django.contrib.sites', # Required by dj-rest-auth
    'allauth', # If you want social auth
    'allauth.account',
    'dj_rest_auth.registration',
]
SITE_ID = 1 # Required for allauth
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' # For testing registration

# urls.py
from django.urls import path, include

urlpatterns = [
    # ...
    path('api/auth/', include('dj_rest_auth.urls')),
    path('api/auth/registration/', include('dj_rest_auth.registration.urls')),
]

# This gives you endpoints like:
# /api/auth/login/
# /api/auth/logout/
# /api/auth/password/reset/
# /api/auth/registration/

8. django-oauth-toolkit

What it is

A library that implements the full OAuth2 provider specification.

Why it's used

Use this when you want your application to act as an OAuth2 provider. This means allowing other applications to access data on behalf of your users, just like you can "Log in with Google" on other sites. Google is acting as the OAuth2 provider in that scenario. This is essential for building platforms that other developers can integrate with.

Core Concepts

  • Provider: Your application, which owns the user data.
  • Resource Owner: The user.
  • Client: The third-party application wanting to access the user's data.
  • Authorization Grant: The process of the user giving permission.

Simple Example

Setting this up is more involved than other auth libraries.

# settings.py
INSTALLED_APPS = [
    # ...
    'oauth2_provider',
]

# urls.py
urlpatterns = [
    # ...
    path('o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
]

# In the Django admin, you would then register a new "Application".
# This represents the third-party client. It will get a `client_id` and `client_secret`.
# A third-party app would then redirect a user to your authorization endpoint:
# /o/authorize/?response_type=code&client_id=...&redirect_uri=...

# A protected API view would look like this:
# views.py
from oauth2_provider.views.generic import ProtectedResourceView
from django.http import HttpResponse

class ApiEndpoint(ProtectedResourceView):
    def get(self, request, *args, **kwargs):
        return HttpResponse('Hello, OAuth2!')

9. djangorestframework-camel-case

What it is

A small utility that automatically converts the snake_case style of Python/Django (e.g., first_name) to the camelCase style of JavaScript (e.g., firstName) in your API's JSON.

Why it's used

It's a convention. JavaScript developers typically work with camelCase, while Python developers use snake_case. This library bridges the gap, converting between the two styles automatically for both incoming requests and outgoing responses, making life easier for your frontend team.

Core Concepts

It provides custom JSON renderers and parsers that you add to your DRF settings.

Simple Example

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        # Use camelCase for API responses
        'djangorestframework_camel_case.render.CamelCaseJSONRenderer',
        'djangorestframework_camel_case.render.CamelCaseBrowsableAPIRenderer',
        # Any other renderers
    ),
    'DEFAULT_PARSER_CLASSES': (
        # Use camelCase for incoming API requests
        'djangorestframework_camel_case.parser.CamelCaseFormParser',
        'djangorestframework_camel_case.parser.CamelCaseMultiPartParser',
        'djangorestframework_camel_case.parser.CamelCaseJSONParser',
        # Any other parsers
    ),
}

# Now, if your model has a field `creation_date`, the API will automatically
# render it as `creationDate` in the JSON response.

10. django-filter

What it is

A reusable app that allows users to filter a queryset dynamically based on URL query parameters.

Why it's used

It makes it trivial to add powerful filtering to your API list views. Instead of manually parsing request.GET parameters and building complex .filter() calls, you define a FilterSet class that does all the work for you. It integrates perfectly with DRF.

Core Concepts

  • FilterSet: A class where you declare which model fields you want to be filterable and what kind of lookups to use (e.g., exact match, contains, greater than).

Simple Example

Let's add filtering to our BookViewSet from example #1.

# filters.py (a new file in your app)
from django_filters import rest_framework as filters
from .models import Book

class BookFilter(filters.FilterSet):
    # Allow filtering by an exact author match
    author = filters.CharFilter(lookup_expr='exact')
    # Allow filtering by title containing a certain string (case-insensitive)
    title = filters.CharFilter(lookup_expr='icontains')

    class Meta:
        model = Book
        fields = ['author', 'title']

# views.py (updated)
from rest_framework import viewsets
from .models import Book
from .serializers import BookSerializer
from .filters import BookFilter # Import the filter
from django_filters.rest_framework import DjangoFilterBackend

class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [DjangoFilterBackend] # Add the filter backend
    filterset_class = BookFilter # Specify your filter class

# Now you can make requests like:
# GET /books/?author=John%20Doe
# GET /books/?title=django

Authentication & User Management

These libraries help you manage who can access your site, how they log in, and what they are allowed to do.

11. django-allauth

What it is

The definitive Django package for handling authentication. It manages both local (username/password) and social (Google, GitHub, etc.) account registration and login.

Why it's used

It's a complete, well-maintained solution that handles all the tricky parts of authentication: registration forms, email verification, password reset, social account linking, and more. Building this yourself is complex and risky.

Core Concepts

  • Providers: Configuration for different social account services (e.g., allauth.socialaccount.providers.google).
  • Adapters: Allow you to customize the behavior of the login/signup flow.

Simple Example

# settings.py
INSTALLED_APPS = [
    # ...
    'django.contrib.sites',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    # Add providers for the services you want
    'allauth.socialaccount.providers.google',
]
SITE_ID = 1
AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
    'allauth.account.auth_backends.AuthenticationBackend',
]
# Redirect to this page after login
LOGIN_REDIRECT_URL = '/'
# Set up Google provider in Django admin or settings
SOCIALACCOUNT_PROVIDERS = {
    'google': {
        'APP': {
            'client_id': 'your-google-client-id',
            'secret': 'your-google-secret',
        },
        'SCOPE': ['profile', 'email'],
    }
}

# urls.py
urlpatterns = [
    path('accounts/', include('allauth.urls')),
]

# In a template:
# {% load socialaccount %}
# <a href="{% provider_login_url 'google' %}">Login with Google</a>

12. django-two-factor-auth

What it is

A library that adds two-factor authentication (2FA) to your Django project, most commonly using TOTP (Time-based One-Time Passwords) apps like Google Authenticator.

Why it's used

2FA adds a critical layer of security. Even if a user's password is stolen, an attacker cannot log in without the second factor (their phone). This is essential for applications handling sensitive data.

Core Concepts

  • TOTP Device: A virtual device (like an app) that generates time-based codes.
  • Backup Tokens: One-time use codes for when the user loses their primary device.

Simple Example

# settings.py
INSTALLED_APPS = [
    # ...
    'django_otp',
    'django_otp.plugins.otp_totp',
    'two_factor',
]
LOGIN_URL = 'two_factor:login' # Override default login URL

# urls.py
from django.urls import path, include
from two_factor.urls import urlpatterns as tf_urls

urlpatterns = [
    path('', include(tf_urls)),
    # ... your other urls
]

# After a user logs in with their password, they will be redirected to a
# page asking for their TOTP token from their authenticator app.
# The library provides all the necessary views and templates for setup and verification.

13. social-auth-app-django

What it is

A flexible and easy-to-setup library for social authentication. It's an alternative to django-allauth.

Why it's used

It's part of the broader python-social-auth ecosystem, which supports many frameworks. Some developers find its "pipeline" concept for customizing the auth flow very powerful and intuitive.

Core Concepts

  • Backends: Similar to allauth's providers, these define the logic for each social service.
  • Pipeline: A series of functions that are executed in order during the authentication process. You can add your own functions to this pipeline to add custom logic (e.g., check if a user belongs to a specific organization).

Simple Example

# settings.py
INSTALLED_APPS = [
    # ...
    'social_django',
]
AUTHENTICATION_BACKENDS = (
    'social_core.backends.github.GithubOAuth2',
    'django.contrib.auth.backends.ModelBackend',
)
LOGIN_REDIRECT_URL = '/'
# Get these from your GitHub OAuth App settings
SOCIAL_AUTH_GITHUB_KEY = 'your-github-key'
SOCIAL_AUTH_GITHUB_SECRET = 'your-github-secret'

# urls.py
urlpatterns = [
    # ...
    path('social/', include('social_django.urls', namespace='social')),
]

# In a template:
# <a href="{% url 'social:begin' 'github' %}">Login with GitHub</a>

14. django-rest-knox

What it is

A token-based authentication library for DRF that prioritizes security and solves some of the common problems with traditional token systems.

Why it's used

Unlike DRF's built-in TokenAuthentication, Knox stores tokens hashed in the database. It also provides per-client tokens, so a user can be logged into multiple devices and log out of one without affecting the others. The tokens themselves are not stored in the database, only a cryptographic hash, which is more secure.

Core Concepts

  • Stateless Tokens: The token is returned to the client only once upon login and is never stored in the database directly.
  • Expiry: Tokens can be configured to auto-expire after a certain period of inactivity.

Simple Example

# views.py
from knox.views import LoginView as KnoxLoginView
from rest_framework.authtoken.serializers import AuthTokenSerializer
from django.contrib.auth import login

class LoginView(KnoxLoginView):
    permission_classes = (AllowAny,)
    def post(self, request, format=None):
        serializer = AuthTokenSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        login(request, user)
        # The super() call handles creating and returning the token
        return super(LoginView, self).post(request, format=None)

# urls.py
from django.urls import path
from knox import views as knox_views
from .views import LoginView

urlpatterns = [
    path('login/', LoginView.as_view(), name='knox_login'),
    # Provides views for logout and logoutall (all devices)
    path('logout/', knox_views.LogoutView.as_view(), name='knox_logout'),
    path('logoutall/', knox_views.LogoutAllView.as_view(), name='knox_logoutall'),
]

15. django-user-sessions

What it is

An extension to Django's built-in session management that makes user sessions more secure and manageable.

Why it's used

It provides features that Django's default session engine lacks. You can see a list of all active sessions for a user, letting them (or an admin) revoke a specific session (e.g., "log out my lost phone"). It also tracks metadata like IP address and user agent for each session.

Core Concepts

It replaces Django's default session engine with its own, which stores session data in the database linked to the user.

Simple Example

# settings.py
# Replace Django's default session engine
SESSION_ENGINE = 'user_sessions.engine.SessionEngine'
INSTALLED_APPS = [
    # ...
    'user_sessions',
]

# That's it for basic setup!
# Now, in a view or template, you can access session information.
# views.py
from django.shortcuts import render
from user_sessions.models import Session

def active_sessions_view(request):
    # Get all active sessions for the currently logged-in user
    user_sessions = Session.objects.filter(user=request.user)
    return render(request, 'sessions.html', {'sessions': user_sessions})

# In sessions.html, you can display session.ip_address, session.user_agent, etc.
# You could add a button to call a view that deletes a specific session.

16. django-invitations

What it is

A simple app to allow user registration via invitations.

Why it's used

For sites that are "invite-only," this library handles the entire flow: generating a unique invitation link, sending it via email, and letting the new user sign up. This is useful for private betas, corporate intranets, or community platforms where you want to control who can join.

Core Concepts

  • Invitation Key: A unique, signed key sent to the invitee.
  • Invitation Model: Stores who invited whom and whether the invitation has been accepted.

Simple Example

# settings.py
INSTALLED_APPS = [
    # ...
    'invitations',
]
ACCOUNT_ADAPTER = 'invitations.models.InvitationsAdapter'
# The email address invitations will be sent from
DEFAULT_FROM_EMAIL = 'invites@yourapp.com'
# Tell allauth to use our adapter
ACCOUNT_ADAPTER = 'invitations.models.InvitationsAdapter'

# urls.py
urlpatterns = [
    path('invitations/', include('invitations.urls', namespace='invitations')),
]

# To send an invitation from a view:
from invitations.models import Invitation

def send_invite(request):
    # Create and send an invitation
    invite = Invitation.create('new_user@example.com', inviter=request.user)
    invite.send_invitation(request)
    # ... return a success message

17. django-guardian

What it is

A library that implements per-object permissions for Django.

Why it's used

Django's built-in permission system is global. A user either has permission to change_task (meaning they can change any task) or they don't. django-guardian lets you grant permissions on a specific object instance. For example, User A can edit Task #1 but not Task #2, while User B can edit Task #2 but not Task #1. This is crucial for collaborative applications.

Core Concepts

  • assign_perm: The function used to grant a permission to a user/group for a specific object.
  • get_objects_for_user: A function to retrieve all objects of a certain type for which a user has a specific permission.

Simple Example

# settings.py
AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'guardian.backends.ObjectPermissionBackend', # Add guardian's backend
)

# views.py
from django.shortcuts import get_object_or_404
from guardian.shortcuts import assign_perm
from .models import Document
from django.contrib.auth.models import User

def share_document(request, doc_id, user_id):
    document = get_object_or_404(Document, pk=doc_id)
    user_to_share_with = get_object_or_404(User, pk=user_id)

    # Grant the 'change_document' permission for this specific document
    assign_perm('change_document', user_to_share_with, document)
    # ...

# To check for permission in a view:
from django.core.exceptions import PermissionDenied

def edit_document(request, doc_id):
    document = get_object_or_404(Document, pk=doc_id)
    if not request.user.has_perm('change_document', document):
        raise PermissionDenied 
    # ... proceed with editing

18. django-axes

What it is

A security library that logs and blocks suspicious login attempts to prevent brute-force attacks.

Why it's used

It's a simple, effective way to secure your login forms. If an IP address or a specific username has too many failed login attempts within a certain time frame, django-axes will temporarily lock them out, making automated password guessing attacks nearly impossible.

Core Concepts

  • Attempt Logging: Records every failed login attempt with IP address and username.
  • Lockout Mechanism: If AXES_FAILURE_LIMIT is reached, future login attempts from that IP/user are blocked for a period of time.

Simple Example

# settings.py
INSTALLED_APPS = [
    # ...
    'axes',
]
AUTHENTICATION_BACKENDS = [
    # Axes must be the first backend
    'axes.backends.AxesStandaloneBackend',
    # Your default backend
    'django.contrib.auth.backends.ModelBackend',
]

# Configure the lockout rules
AXES_FAILURE_LIMIT = 5 # Lockout after 5 failed attempts
AXES_COOLOFF_TIME = 1 # Lockout for 1 hour
AXES_LOCKOUT_TEMPLATE = 'locked.html' # Show this template when locked out

# That's it! Axes automatically hooks into the authentication signals.
# You can view failed attempts and locked-out users in the Django admin.

Admin Interface Enhancements

These libraries improve the functionality and appearance of Django's built-in admin site, making it more powerful and user-friendly for site administrators.

19. django-import-export

What it is

A library that allows you to add import and export functionality for data directly within the Django admin interface.

Why it's used

It's incredibly useful for bulk-adding new data from spreadsheets (CSV, XLSX, etc.) or for backing up data from specific models into a file. It saves you from having to write custom scripts for data migration tasks.

Core Concepts

  • Resource: A class that maps your Django model to a specific import/export format, defining which fields are included and how they are handled.
  • ModelAdmin Integration: You link your Resource to your ModelAdmin class to enable the import/export buttons in the admin.

Simple Example

# admin.py
from django.contrib import admin
from .models import Book
from import_export import resources
from import_export.admin import ImportExportModelAdmin

# 1. Create a Resource class for your model
class BookResource(resources.ModelResource):
    class Meta:
        model = Book

# 2. Create a ModelAdmin that uses ImportExportModelAdmin
class BookAdmin(ImportExportModelAdmin):
    resource_class = BookResource
    list_display = ('title', 'author')

# 3. Unregister the default admin and register your new one
# admin.site.unregister(Book) # If Book was already registered
admin.site.register(Book, BookAdmin)

# Now, the Book list view in the admin will have "Import" and "Export" buttons.

20. Django Grappelli

What it is

A popular and highly customizable "skin" or theme for the Django admin interface.

Why it's used

It provides a cleaner, more modern look and feel than the default admin theme. It includes features like a collapsible menu and an improved dashboard layout, making the admin easier to navigate, especially in projects with many apps and models.

Core Concepts

It overrides Django's default admin templates and static files to provide its own styling and layout.

Simple Example

# settings.py
INSTALLED_APPS = [
    'grappelli', # Must be BEFORE 'django.contrib.admin'
    'django.contrib.admin',
    # ... other apps
]

# urls.py
from django.urls import path, include

urlpatterns = [
    # Grappelli's URLs must come before the admin URLs
    path('grappelli/', include('grappelli.urls')),
    path('admin/', admin.site.urls),
]

# After running `collectstatic`, your admin interface at /admin/ will now have the Grappelli theme applied.

21. Django Jet Reboot

What it is

A modern, responsive theme for the Django admin interface with a focus on a clean user experience. It's a reboot of the older django-jet.

Why it's used

It offers a significant visual overhaul of the admin, making it look more like a modern web application. It's fully responsive, working well on both desktop and mobile devices. It also has features like a collapsible sidebar and theme customization options.

Core Concepts

Similar to Grappelli, it replaces the admin's templates and static files.

Simple Example

# settings.py
INSTALLED_APPS = [
    'jet', # Must be BEFORE 'django.contrib.admin'
    'django.contrib.admin',
    # ... other apps
]

# urls.py
from django.urls import path, include

urlpatterns = [
    path('jet/', include('jet.urls', 'jet')),  # Django JET URLS
    path('admin/', admin.site.urls),
    # ...
]

# After installation and running `collectstatic`, your admin will use the Jet theme.
# You can configure themes and other settings in the admin itself.

22. Unfold

What it is

A new, modern, and highly customizable theme for the Django admin built with Tailwind CSS.

Why it's used

It provides a very fresh and contemporary look, leveraging the power and flexibility of Tailwind CSS. It's designed to be easily customized through Django settings, allowing you to change colors, logos, and layouts without writing custom CSS. It also includes nice features like sidebar navigation and component styling.

Core Concepts

A complete replacement for the admin's frontend, built with modern tooling.

Simple Example

# settings.py
INSTALLED_APPS = [
    "unfold",  # Must be before django.contrib.admin
    "unfold.apps.SideMenu", # For the sidebar
    # ... your other apps
    "django.contrib.admin",
]

# There's no need to change urls.py.
# Unfold automatically takes over the /admin/ route.
# You can customize it via settings:
UNFOLD = {
    "SITE_TITLE": "My Awesome Project",
    "SITE_HEADER": "My Awesome Project Admin",
    # ... many more customization options
}

23. django-simple-history

What it is

A library that automatically tracks changes to your Django models and stores the history in the database.

Why it's used

It provides a complete audit log of who changed what and when for any model you choose. You can see every version of a model instance, see what fields changed between versions, and even revert the object to a previous state. This is invaluable for auditing, debugging, and accountability.

Core Concepts

  • HistoricalRecords: A manager you add to your model to enable history tracking. It creates a new "historical" model behind the scenes.

Simple Example

# models.py
from django.db import models
from simple_history.models import HistoricalRecords

class BlogPost(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    status = models.CharField(max_length=20)
    history = HistoricalRecords() # This enables history tracking

# Now, every time a BlogPost instance is created, updated, or deleted,
# a new record is saved in a separate `historicalblogpost` table.
# Example of accessing history in the shell or a view:
# >>> post = BlogPost.objects.get(pk=1)
# >>> post.title = "A New Title"
# >>> post.save()
# >>> post.history.all()
# <QuerySet [<HistoricalBlogPost: BlogPost object (1) as of 2025-07-21 11:45:00>, <HistoricalBlogPost: BlogPost object (1) as of 2025-07-21 11:44:00>]>

24. django-admin-honeypot

What it is

A security tool that creates a fake Django admin login page at the default /admin/ URL to trap bots and attackers.

Why it's used

Automated bots constantly scan the web for common login URLs like /admin/. This library logs their attempts to log in to the fake page, notifying you of the attack without exposing your real login page. Your real admin login is moved to a different, secret URL.

Core Concepts

It sets up a decoy view at /admin/ and expects you to move your real admin to a new URL.

Simple Example

# settings.py
INSTALLED_APPS = [
    # ...
    'admin_honeypot',
]

# urls.py
from django.urls import path

urlpatterns = [
    # ...
    # Your REAL admin login is at a secret URL now
    path('secret-admin-panel/', admin.site.urls),
    # The fake honeypot is at the default admin URL
    path('admin/', include('admin_honeypot.urls', namespace='admin_honeypot')),
]

# Now, any attempt to log in at /admin/ will be logged in the database
# (visible in your real admin panel) and the attacker will see a fake
# "invalid login" message.

25. django-object-actions

What it is

A library that lets you add actions to the Django admin on a per-object basis, both in the list view (changelist) and the detail view (change form).

Why it's used

Django's default admin actions operate on a queryset (e.g., "delete selected items"). This library lets you add buttons that perform an action on a single object instance, like "Approve this post" or "Send reminder email".

Core Concepts

You add a mixin to your ModelAdmin and define methods that represent your actions.

Simple Example

# admin.py
from django.contrib import admin
from django_object_actions import DjangoObjectActions
from .models import Article

@admin.register(Article)
class ArticleAdmin(DjangoObjectActions, admin.ModelAdmin):
    list_display = ('title', 'status')

    # Define an action method
    def publish_article(self, request, obj):
        obj.status = 'published'
        obj.save()
    # Configure the action's appearance
    publish_article.label = "Publish" # Button label
    publish_article.short_description = "Publish this article" # Tooltip

    # Add the action to both the detail view and list view
    change_actions = ('publish_article',)
    changelist_actions = ('publish_article',)

# Now, in the admin, each article will have a "Publish" button next to it.

26. django-baton

What it is

Another modern, responsive, and highly customizable theme for the Django admin.

Why it's used

It's a strong alternative to Jet and Unfold, offering a clean interface, powerful configuration options (via settings.py), and a focus on usability. It includes features like custom menu organization, a robust search bar, and easy branding.

Core Concepts

Like other themes, it replaces the admin's frontend assets and templates.

Simple Example

# settings.py
INSTALLED_APPS = [
    'baton', # Must be before django.contrib.admin
    'django.contrib.admin',
    #...
    'baton.autodiscover', # Optional, for automatic menu generation
]

# Configure Baton in your settings
BATON = {
    'SITE_TITLE': 'My Project Admin',
    'SITE_HEADER': '<img src="/static/logo.png" />', # Custom logo
    'MENU_TITLE': 'Main Menu',
    # ... many more options
}

# urls.py
urlpatterns = [
    #...
    path('admin/', include('baton.urls')),
]

# After `collectstatic`, your admin will have the Baton theme.

27. django-admin-rangefilter

What it is

A small library that adds a filter to the admin list view for numeric and date ranges.

Why it's used

Django's default admin filters are limited (e.g., "any date," "today," "past 7 days"). This library lets you add a filter where the admin user can select a custom date range (e.g., from January 15th to March 10th) or a numeric range (e.g., show products with prices between $50 and $100).

Core Concepts

It provides custom ListFilter classes that you add to your ModelAdmin.

Simple Example

# admin.py
from django.contrib import admin
from .models import Order
# Import the custom filters
from rangefilter.filters import DateRangeFilter, NumericRangeFilter

@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
    list_display = ('id', 'customer_name', 'order_date', 'total_amount')
    # Add the range filters to the list_filter tuple
    list_filter = (
        ('order_date', DateRangeFilter),
        ('total_amount', NumericRangeFilter),
    )

# In the Order admin list, you will now have interactive filters for
# "Order Date (range)" and "Total Amount (range)".

Database & ORM Extensions

These libraries enhance or extend the capabilities of Django's Object-Relational Mapper (ORM), add support for different databases, or provide useful model-level utilities.

28. psycopg / psycopg2-binary

What it is

The most popular and robust database adapter for connecting Python applications to a PostgreSQL database. psycopg is the modern version, while psycopg2 is the long-standing predecessor.

Why it's used

If you want to use PostgreSQL as your database with Django (which is highly recommended for production applications), you must have this library installed. It's the bridge that allows Django's ORM to communicate with the PostgreSQL server.

Core Concepts

It's a low-level driver. You don't interact with it directly; Django uses it behind the scenes.

Simple Example

The usage is entirely in your settings.py.

# settings.py

# You just need to install it: pip install psycopg
# Or for the older version: pip install psycopg2-binary

# Then configure Django to use it
DATABASES = {
    'default': {
        # Use the PostgreSQL backend engine
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydatabase',
        'USER': 'myuser',
        'PASSWORD': 'mypassword',
        'HOST': 'localhost', # or your db host
        'PORT': '5432',
    }
}

# With this setting, all of Django's ORM operations (e.g., MyModel.objects.all())
# will be translated into SQL and sent to PostgreSQL via psycopg.

29. django-extensions

What it is

An indispensable collection of custom management commands, shell enhancements, and other developer utilities.

Why it's used

It provides a suite of tools that make development faster and more pleasant. Its most famous feature is shell_plus, which is a huge upgrade over the standard Django shell.

Core Concepts

It adds new commands you can run with python manage.py <command_name>.

Key Features & Example

  • shell_plus: Automatically imports all your Django models and other useful utilities when it starts, so you don't have to type from myapp.models import MyModel over and over.
    # Just run this command
    python manage.py shell_plus
    # It also integrates with iPython/bpython for a better shell experience.
  • runserver_plus: A replacement for the standard runserver that includes the Werkzeug debugger, which gives you an interactive debugging console in your browser when an error occurs.
  • graph_models: Generates a graph visualization of your project's models, which is great for understanding database relationships.
    python manage.py graph_models -a -o my_models.png
  • show_urls: Displays all the URL patterns in your project, which is very helpful for debugging routing issues.

30. django-model-utils

What it is

A library that provides a collection of common, reusable patterns and fields for Django models.

Why it's used

It helps you adhere to the DRY (Don't Repeat Yourself) principle. Instead of defining the same created_at and updated_at fields on every model, you can just inherit from TimeStampedModel.

Core Concepts

It provides abstract models and custom model fields that encapsulate common behaviors.

Simple Example

Using TimeStampedModel.

# models.py
from django.db import models
from model_utils.models import TimeStampedModel

# Instead of this:
# class Post(models.Model):
#     title = models.CharField(max_length=100)
#     created = models.DateTimeField(auto_now_add=True)
#     modified = models.DateTimeField(auto_now=True)

# You can do this:
class Post(TimeStampedModel):
    title = models.CharField(max_length=100)

# The Post model will automatically have `created` and `modified` fields
# that are managed for you. It's cleaner and less repetitive.
# Other useful features include StatusField, Choices, and more.

31. django-mptt

What it is

A library that makes it easy and efficient to work with hierarchical (tree-like) data in Django. MPTT stands for Modified Preorder Tree Traversal.

Why it's used

Storing and querying hierarchical data (like categories with sub-categories, or forum comments with replies) is inefficient with simple parent-child foreign keys. MPTT uses a clever algorithm that makes retrieving all descendants of a node (e.g., all sub-categories) extremely fast with a single database query.

Core Concepts

  • MPTTModel: A model class you inherit from.
  • TreeForeignKey: A special foreign key to link a node to its parent.

Simple Example

# models.py
from django.db import models
from mptt.models import MPTTModel, TreeForeignKey

class Category(MPTTModel):
    name = models.CharField(max_length=50, unique=True)
    # The parent field links a category to its parent category
    parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')

    class MPTTMeta:
        order_insertion_by = ['name']

# Now you can easily work with tree structures:
# >>> electronics = Category.objects.create(name='Electronics')
# >>> phones = Category.objects.create(name='Phones', parent=electronics)
# >>> laptops = Category.objects.create(name='Laptops', parent=electronics)
# >>> smartphones = Category.objects.create(name='Smartphones', parent=phones)
#
# >>> electronics.get_descendants()
# <TreeQuerySet [<Category: Laptops>, <Category: Phones>, <Category: Smartphones>]>

32. django-taggit

What it is

A simple but powerful library for adding tags to your Django models.

Why it's used

It provides a very easy way to implement tagging functionality, similar to what you see on blogs or photo sites. It handles creating the tag models, the many-to-many relationship, and provides a simple API for adding, removing, and filtering by tags.

Core Concepts

  • TaggableManager: A manager you add to your model to make it "taggable".

Simple Example

# models.py
from django.db import models
from taggit.managers import TaggableManager

class BlogPost(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    tags = TaggableManager() # And you're done!

# Example usage:
# >>> post = BlogPost.objects.create(title="My First Post", content="...")
# >>> post.tags.add("django", "python", "webdev")
# >>> post.tags.all()
# <QuerySet [<Tag: python>, <Tag: django>, <Tag: webdev>]>
#
# >>> # Find all posts tagged with 'python'
# >>> BlogPost.objects.filter(tags__name__in=["python"])

33. django-reversion

What it is

A library that provides version control for your model instances, similar to a wiki or a version control system like Git.

Why it's used

It's more powerful than django-simple-history for scenarios where you want to group changes together into "revisions" or "commits". For example, if updating a BlogPost also involves updating its Tags, you can save both changes in a single revision. This is excellent for creating audit trails and enabling reliable undo/redo functionality.

Core Concepts

  • Revisions: You wrap your code in a reversion.create_revision() block. All model changes made inside this block are saved as a single atomic revision.
  • Registration: You must register the models you want to track with reversion.

Simple Example

# models.py
import reversion
from django.db import models

@reversion.register() # Register the model for version control
class Article(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()

# views.py
import reversion

def update_article(request, pk):
    article = Article.objects.get(pk=pk)
    # Group changes into a single revision
    with reversion.create_revision():
        article.title = request.POST.get('title')
        article.content = request.POST.get('content')
        article.save()

        # Store metadata about the change
        reversion.set_user(request.user) 
        reversion.set_comment("Updated title and content.")

34. django-fsm

What it is

A library that allows you to add finite-state machine (FSM) support to your Django models.

Why it's used

It's perfect for managing models that have a 'status' or 'state' that can only change in specific, defined ways (a workflow). For example, a blog post can go from 'draft' to 'in review', but not directly to 'published'. django-fsm enforces these transition rules at the model level, preventing invalid state changes.

Core Concepts

  • FSMField: A special field to store the state of the model.
  • @transition: A decorator for model methods that defines a valid state change from a source state to a target state.

Simple Example

# models.py
from django.db import models
from django_fsm import FSMField, transition

class BlogPost(models.Model):
    title = models.CharField(max_length=200)
    # The FSMField stores the current state
    state = FSMField(default='draft')

    # A method decorated as a transition
    @transition(field=state, source='draft', target='submitted')
    def submit_for_review(self):
        # ... code to run during transition, like sending a notification
        pass

    @transition(field=state, source='submitted', target='published')
    def publish(self):
        # ...
        pass

# Usage:
# >>> post = BlogPost.objects.create(title='My Post')
# >>> post.state
# 'draft'
# >>> post.submit_for_review() # This is allowed
# >>> post.state
# 'submitted'
# >>> post.publish() # This is allowed
# >>> post.state
# 'published'
# >>> post.submit_for_review() # This will raise an exception because the source state is not 'draft'

35. django-polymorphic

What it is

A library that simplifies the use of model inheritance in Django.

Why it's used

With standard Django model inheritance, if you query the base model, you only get the fields from the base model. You have to do extra work to figure out the specific child model type and access its fields. django-polymorphic handles this automatically. When you query the base model, it returns a queryset of child model instances, so you can access their specific fields directly.

Core Concepts

  • PolymorphicModel: The base model class you inherit from.
  • Automatic Downcasting: The process of automatically converting a base model instance to its correct child model type.

Simple Example

# models.py
from django.db import models
from polymorphic.models import PolymorphicModel

# Base model
class Project(PolymorphicModel):
    topic = models.CharField(max_length=30)

# Two different child models
class ArtProject(Project):
    artist = models.CharField(max_length=30)

class ResearchProject(Project):
    supervisor = models.CharField(max_length=30)

# Usage:
# >>> ArtProject.objects.create(topic='Still Life', artist='Monet')
# >>> ResearchProject.objects.create(topic='Quantum Physics', supervisor='Einstein')
#
# >>> # Querying the base model returns polymorphic results!
# >>> for project in Project.objects.all():
# ...     # You can access both base and child fields directly
# ...     if isinstance(project, ArtProject):
# ...         print(f"Art Project: '{project.topic}' by {project.artist}")
# ...     elif isinstance(project, ResearchProject):
# ...         print(f"Research Project: '{project.topic}' supervised by {project.supervisor}")

36. django-money

What it is

A library that adds a MoneyField to Django for handling monetary values and their currencies.

Why it's used

Storing money as a FloatField is a bad idea due to floating-point precision errors. django-money uses Python's Decimal type for accuracy and bundles the currency with the amount. This prevents mistakes and makes currency conversions and formatting simple.

Core Concepts

  • MoneyField: A composite field that stores both a Decimal amount and a currency code in your database.
  • Money object: A Python object that holds both the amount and the currency.

Simple Example

# models.py
from django.db import models
from djmoney.models.fields import MoneyField

class Product(models.Model):
    name = models.CharField(max_length=100)
    price = MoneyField(
        max_digits=10,
        decimal_places=2,
        default_currency='USD'
    )

# Usage:
# >>> from djmoney.money import Money
# >>> product = Product.objects.create(name='Laptop', price=Money(1200, 'USD'))
# >>> product.price
# Money('1200.00', 'USD')
# >>> print(product.price)
# $1,200.00
#
# >>> another_product = Product.objects.create(name='Book', price=25.50) # Uses default currency
# >>> another_product.price
# Money('25.50', 'USD')

37. django-phonenumber-field

What it is

A model and form field for storing, validating, and displaying international phone numbers.

Why it's used

It leverages the phonenumbers (a Python port of Google's libphonenumber) library to handle the complexities of international phone number formats. It ensures that only valid phone numbers are stored and can format them consistently (e.g., as E.164 standard +41446681800).

Core Concepts

  • PhoneNumberField: The model field that stores the phone number.

Simple Example

# models.py
from django.db import models
from phonenumber_field.modelfields import PhoneNumberField

class Profile(models.Model):
    user = models.OneToOneField('auth.User', on_delete=models.CASCADE)
    # Can store phone numbers from any country
    phone_number = PhoneNumberField(blank=True, help_text='Contact phone number')

# In a form, it renders a text input.
# It will validate that the input is a plausible phone number.
#
# Usage:
# >>> profile = Profile.objects.get(pk=1)
# >>> profile.phone_number
# PhoneNumber(country_code=1, national_number=2125552368, extension=None)
# >>> profile.phone_number.as_international
# '+1 212-555-2368'
# >>> profile.phone_number.as_e164
# '+12125552368'

38. django-countries

What it is

A Django app that provides country choices for use with forms and models.

Why it's used

It saves you from having to create and maintain your own list of world countries. It provides a CountryField that renders as a dropdown select of all countries and stores the standard two-letter ISO 3166-1 country code (e.g., 'US', 'GB', 'IN').

Core Concepts

  • CountryField: A field that provides a list of countries as its choices.

Simple Example

# models.py
from django.db import models
from django_countries.fields import CountryField

class Address(models.Model):
    street = models.CharField(max_length=100)
    city = models.CharField(max_length=100)
    country = CountryField(blank_label='(select country)')

# In a Django form, this `country` field will automatically render as a
# <select> dropdown populated with all the countries.
#
# Usage:
# >>> address = Address.objects.create(street="123 Main St", city="Anytown", country="US")
# >>> address.country
# Country(code='US')
# >>> address.country.name
# 'United States'
# >>> address.country.flag
# '🇺🇸'

Development Tools & Debugging

These tools don't usually become part of your final deployed application but are essential during the development process for debugging, code quality, and productivity.

39. django-debug-toolbar

What it is

An indispensable toolbar that appears on your site during development, showing a vast amount of debugging information about the current request/response.

Why it's used

It's the #1 tool for debugging Django applications. It tells you exactly which SQL queries were run and how long they took, which templates were rendered, what's in your settings, cache performance, and much more. It's the fastest way to diagnose performance problems (like the N+1 query problem).

Core Concepts

It's implemented as Django middleware, so it inspects every request and response cycle.

Simple Example

Setup is done in settings.py and urls.py.

# settings.py
INSTALLED_APPS = [
    # ...
    "debug_toolbar",
]
MIDDLEWARE = [
    # ...
    "debug_toolbar.middleware.DebugToolbarMiddleware",
    # ...
]
# You need to configure the IP addresses that are allowed to see the toolbar
INTERNAL_IPS = [
    "127.0.0.1",
]

# urls.py
import debug_toolbar
from django.urls import include, path

urlpatterns = [
    # ... your other urls
    path("__debug__/", include(debug_toolbar.urls)),
]

# Now, when you run your dev server and visit a page, a floating panel will
# appear on the side of your screen.

40. django-silk

What it is

A live profiling and inspection tool for Django applications.

Why it's used

While the Debug Toolbar is great for per-page analysis, Silk is fantastic for profiling API endpoints and identifying performance bottlenecks in your code. It intercepts and records HTTP requests and database queries and provides a clean UI to inspect the results, showing exactly where time is being spent within your views.

Core Concepts

It's a middleware that records profiling data for each request.

Simple Example

# settings.py
INSTALLED_APPS = [
    # ...
    'silk',
]
MIDDLEWARE = [
    # ...
    'silk.middleware.SilkyMiddleware',
    # ...
]

# urls.py
urlpatterns += [path('silk/', include('silk.urls', namespace='silk'))]

# Now, as you use your application (especially API endpoints), Silk will
# record data in the background. Visit `/silk/` to see the dashboard
# with detailed reports on request times, SQL queries, and code profiling.

41. Sentry-sdk

What it is

A client for the Sentry service, which provides real-time error tracking and performance monitoring for your applications.

Why it's used

In a live production environment, you need to know immediately when things go wrong. Sentry captures unhandled exceptions in your Django app, groups them, and alerts you with rich context (like the user affected, the request data, etc.). This allows you to find and fix bugs before your users even report them.

Core Concepts

You initialize the SDK in your settings, and it automatically hooks into Django's logging and exception handling.

Simple Example

# settings.py
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration

# You get the DSN from your Sentry.io project settings
SENTRY_DSN = "https://examplePublicKey@o0.ingest.sentry.io/0"

# Only initialize Sentry in production environments
if not DEBUG:
    sentry_sdk.init(
        dsn=SENTRY_DSN,
        integrations=[DjangoIntegration()],
        # Set traces_sample_rate to 1.0 to capture 100% of transactions for performance monitoring.
        traces_sample_rate=1.0,
        # Send personal data for better debugging context
        send_default_pii=True
    )

# Now, if an unhandled error occurs in production, it will be automatically
# sent to your Sentry dashboard.

42. Black

What it is

An uncompromising, deterministic Python code formatter.

Why it's used

It ends all debates about code style. Black automatically reformats your Python code to its own strict, consistent style. This means your team spends zero time arguing about formatting in code reviews and can focus on what the code actually does. The resulting code is always clean and readable.

Core Concepts

It's a command-line tool that you run on your codebase.

Simple Example

# Install black
# pip install black

# Run it on a specific file
black my_app/views.py

# Run it on your entire project directory
black .

# Example of what it does:
# Before black:
# my_dict = { "a":1,  'b':  2   }
#
# After running `black`:
# my_dict = {"a": 1, "b": 2}

43. Flake8

What it is

A tool that checks your Python code for errors and style violations.

Why it's used

It's a "linter." It helps you catch common programming errors (like unused imports or undefined variables) and ensures your code adheres to the PEP 8 style guide. Using Flake8 leads to higher-quality, more maintainable code and helps prevent simple bugs.

Core Concepts

It's a command-line tool that analyzes your code without running it.

Simple Example

# Install flake8
# pip install flake8

# Run it on your project
flake8 .

# It will print out a list of errors and their locations, for example:
# my_app/models.py:1:1: F401 'django.db.models' imported but unused
# my_app/views.py:10:80: E501 line too long (88 > 79 characters)
#
# You can configure it with a `.flake8` file in your project root.

44. iPython

What it is

A powerful, interactive Python shell that is a vast improvement over the default Python REPL.

Why it's used

It provides features like tab completion, syntax highlighting, object introspection, and easy access to command history, making interactive work much more efficient. When used with django-extensions, the shell_plus command will automatically use iPython if it's installed, giving you a supercharged Django shell.

Core Concepts

It's an enhanced Read-Eval-Print Loop (REPL).

Simple Example

The best way to use it with Django is via django-extensions.

# Install django-extensions and ipython
# pip install django-extensions ipython

# Run shell_plus
python manage.py shell_plus

# You are now in an iPython shell with all your models pre-imported.
# You can type `User.` and press Tab to see all available methods and attributes.

45. pre-commit

What it is

A framework for managing and maintaining multi-language pre-commit hooks.

Why it's used

It ensures that certain checks (like running black and flake8) are performed on your code before you are allowed to commit it to Git. This automatically enforces code quality and style for everyone on the team and prevents messy code from ever entering the repository.

Core Concepts

You define a .pre-commit-config.yaml file that lists the hooks you want to run.

Simple Example

# .pre-commit-config.yaml
repos:
-   repo: https://github.com/psf/black
    rev: 24.4.2 # Use a specific version
    hooks:
    -   id: black
-   repo: https://github.com/pycqa/flake8
    rev: 7.1.0
    hooks:
    -   id: flake8

# Install pre-commit
# pip install pre-commit

# Set up the git hooks
pre-commit install

# Now, when you run `git commit`, pre-commit will run black and flake8 on the
# files you've changed. If they fail, the commit will be aborted until you
# fix the issues.

46. Rich

What it is

A Python library for rendering rich text and beautiful formatting in the terminal.

Why it's used

It makes terminal output much more readable and visually appealing. It can render text with colors and styles, create tables, progress bars, markdown, and syntax-highlighted code. Libraries like django-extensions and typer use Rich to improve their command-line interfaces.

Core Concepts

You create a Console object and use its print method.

Simple Example

Can be used in management commands or scripts.

from rich.console import Console

console = Console()

# Simple printing with colors and styles
console.print("This is some text.", style="bold red")

# It can print complex objects beautifully
my_dict = {"name": "Gemini", "features": ["code", "text", "translation"]}
console.print(my_dict)

# It also powers the pretty tracebacks in `runserver_plus` from django-extensions.

47. Faker

What it is

A Python library for generating fake data.

Why it's used

When you need to populate your database for testing or development, you need realistic-looking data. Faker can generate fake names, addresses, phone numbers, email addresses, paragraphs of text, and much more. This is essential for creating test databases that resemble a real production environment.

Core Concepts

You create a Faker instance and call its provider methods.

Simple Example

Creating users in a management command.

# my_app/management/commands/seed_users.py
from django.core.management.base import BaseCommand
from django.contrib.auth.models import User
from faker import Faker

class Command(BaseCommand):
    help = 'Seeds the database with fake users'

    def handle(self, *args, **options):
        fake = Faker()
        self.stdout.write("Creating 10 fake users...")
        for _ in range(10):
            first_name = fake.first_name()
            last_name = fake.last_name()
            User.objects.create_user(
                username=fake.user_name(),
                email=fake.email(),
                password='password123',
                first_name=first_name,
                last_name=last_name
            )
        self.stdout.write(self.style.SUCCESS('Successfully created 10 users.'))

Forms & Frontend Integration

These libraries bridge the gap between your Django backend and the frontend (the user's browser), helping you render forms, tables, and manage frontend assets like CSS and JavaScript.

48. django-crispy-forms

What it is

A library that gives you precise control over how your Django forms are rendered, without writing tedious HTML in your templates.

Why it's used

By default, rendering a Django form with {{ form.as_p }} is inflexible. django-crispy-forms lets you add a simple |crispy filter to your form in the template, and it will render it beautifully using a template pack like Bootstrap or Tailwind CSS. You can easily customize the form layout in your Python code.

Core Concepts

  • Template Packs: Sets of templates that define how forms are rendered for a specific CSS framework (e.g., crispy-bootstrap5).
  • |crispy filter: The template filter you apply to render the form.
  • Layout Helpers: Python classes you can use to define complex form layouts (e.g., fields side-by-side, accordions).

Simple Example

# settings.py
INSTALLED_APPS = [
    # ...
    "crispy_forms",
    "crispy_bootstrap5", # Or your chosen template pack
]
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"

# forms.py
from django import forms
class MyForm(forms.Form):
    name = forms.CharField()
    email = forms.EmailField()

# my_template.html
<!-- {% load crispy_forms_tags %} -->
<form method="post">
    <!-- {% csrf_token %} -->
    {{ form|crispy }}
    <button type="submit">Submit</button>
</form>
# This will render the form with proper Bootstrap 5 divs, labels, and classes.

49. django-tables2

What it is

[span_0]

A library for creating and rendering HTML tables from a queryset or other data source.[span_0]

Why it's used

Manually writing a for loop in a template to create a table is repetitive. django-tables2 automates this. You define a Table class in Python, and it handles rendering the <table>, <thead>, <tbody>, pagination, and column sorting for you.

Core Concepts

  • Table class: A class where you define the columns of your table, linking them to your model's fields.

Simple Example

# tables.py (new file in your app)
import django_tables2 as tables
from .models import Book

class BookTable(tables.Table):
    class Meta:
        model = Book
        # Specify fields to include and their order
        fields = ("title", "author")
        template_name = "django_tables2/bootstrap5.html" # Use a nice theme

# views.py
from django.shortcuts import render
from .models import Book
from .tables import BookTable

def book_list_view(request):
    table = BookTable(Book.objects.all())
    return render(request, "book_list.html", {"table": table})

# book_list.html
<!-- {% load django_tables2 %} -->
<!-- {% render_table table %} -->
# This will render a full HTML table with sorting headers.

50. django-htmx

What it is

A library that seamlessly integrates the htmx JavaScript library into Django.

Why it's used

htmx allows you to build modern, dynamic user interfaces without writing complex JavaScript. You add special hx- attributes to your HTML, and htmx will make AJAX requests to your Django views and swap parts of the page with the HTML fragments your views return. [span_7]It's a powerful way to add interactivity (like live search, infinite scroll, etc.) while staying within the Django template ecosystem.[span_7]

Core Concepts

  • Partial HTML Responses: Your Django views return small snippets of HTML instead of a full page refresh.
  • hx- attributes: HTML attributes like hx-get, hx-post, hx-trigger, and hx-target that control htmx's behavior.

Simple Example

A simple "Load More" button.

# views.py
def load_more_books(request):
    # This view only returns a fragment of HTML
    books = Book.objects.all()[3:] # Get the next set of books
    return render(request, 'partials/book_rows.html', {'books': books})

# my_template.html
<tbody id="book-table-body">
    <!-- {% for book in initial_books %} -->
    <!--     {% include 'partials/book_rows.html' %} -->
    <!-- {% endfor %} -->
</tbody>
<button hx-get="{% url 'load_more_books' %}"
        hx-target="#book-table-body"
        hx-swap="beforeend">
    Load More
</button>
# When clicked, htmx gets the HTML from the URL and appends it to the table body.

51. django-webpack-loader

What it is

A tool to integrate bundles generated by Webpack (a popular JavaScript module bundler) into your Django templates.

Why it's used

In modern web development, frontend assets (JavaScript, CSS) are often processed by tools like Webpack. Webpack creates optimized "bundle" files with unique hashes in their names for caching (e.g., main.a8fde9.js). django-webpack-loader reads a manifest file generated by Webpack to figure out the correct filename and includes it in your template.

Core Concepts

  • Webpack: A separate tool that bundles your JS/CSS.
  • render_bundle: The template tag that reads the manifest and inserts the correct <script> or <link> tag.

Simple Example

# settings.py (configure where to find the manifest file)
WEBPACK_LOADER = {
    'DEFAULT': {
        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
    }
}

# my_template.html
<!-- {% load render_bundle from webpack_loader %} -->
<html>
<head>
    <!-- {% render_bundle 'main' 'css' %} -->
</head>
<body>
    <!-- {% render_bundle 'main' 'js' %} -->
</body>
</html>
# This will be rendered as:
# <link type="text/css" href="/static/main.b9cda8.css" rel="stylesheet">
# <script src="/static/main.a8fde9.js"></script>

52. django-widget-tweaks

What it is

A small library that allows you to tweak a form field's rendering directly in your template.

Why it's used

Sometimes you just need to add a CSS class, a placeholder attribute, or another HTML attribute to a Django form field without creating a whole new custom widget in Python. django-widget-tweaks lets you do this with a simple template filter or tag.

Core Concepts

  • render_field tag: The primary tool for rendering a field and adding attributes.

Simple Example

# my_template.html
<!-- {% load widget_tweaks %} -->

<!-- {% render_field form.email class="form-control" placeholder="your@email.com" %} -->

<!-- {% render_field form.comment rows="5" class+=" my-custom-class" %} -->

53. django-compressor

What it is

A library that compresses (minifies) and combines your linked and inline JavaScript or CSS into a single cached file.

Why it's used

To improve website performance. Combining multiple CSS or JS files into one reduces the number of HTTP requests the browser has to make. Minifying the files (removing whitespace and comments) reduces their size. Both lead to faster page load times.

Core Concepts

  • compress template tag: You wrap your <script> and <link> tags with this, and django-compressor handles the rest.

Simple Example

# settings.py
INSTALLED_APPS = [
    # ...
    'compressor',
]
STATICFILES_FINDERS = (
    # ...
    'compressor.finders.CompressorFinder',
)
COMPRESS_ENABLED = True # Make sure to enable it

# my_template.html
<!-- {% load compress %} -->

<!-- {% compress css %} -->
<link rel="stylesheet" href="/static/css/base.css">
<link rel="stylesheet" href="/static/css/forms.css">
<!-- {% endcompress %} -->

<!-- {% compress js %} -->
<script src="/static/js/vendor/jquery.js"></script>
<script src="/static/js/main.js"></script>
<!-- {% endcompress %} -->

# In production, this will render a single `<link>` and a single `<script>` tag
# pointing to the compressed, combined files.

54. django-autocomplete-light

What it is

A library that simplifies the creation of autocomplete widgets for form fields, especially for ForeignKey or ManyToManyField.

Why it's used

When a ForeignKey can point to thousands of items (e.g., choosing a user from a list of 50,000), a standard <select> dropdown is unusable. This library provides a widget that makes an AJAX call to the server as the user types, showing a list of matching options.

Core Concepts

  • Autocomplete View: A Django view you create that receives the search term and returns a JSON list of matching items.
  • Autocomplete Widget: A form widget that you assign to your model field.

Simple Example

# views.py (or a dedicated autocomplete.py)
from dal import autocomplete
from .models import Country

class CountryAutocomplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        qs = Country.objects.all()
        if self.q: # The search term from the user
            qs = qs.filter(name__icontains=self.q)
        return qs

# forms.py
from dal import autocomplete
from .models import Person

class PersonForm(forms.ModelForm):
    class Meta:
        model = Person
        fields = '__all__'
        widgets = {
            'birth_country': autocomplete.ModelSelect2(url='country-autocomplete')
        }

# urls.py
# path('country-autocomplete/', CountryAutocomplete.as_view(), name='country-autocomplete'),

55. django-crispy-tailwind

What it is

A template pack for django-crispy-forms that allows it to render forms with Tailwind CSS classes.

Why it's used

If your project uses Tailwind CSS instead of Bootstrap, you need this library to make django-crispy-forms output the correct class names and HTML structure for your forms to be styled correctly.

Core Concepts

It's a configuration-level library that provides the necessary templates for crispy-forms.

Simple Example

# settings.py
INSTALLED_APPS = [
    # ...
    "crispy_forms",
    "crispy_tailwind", # The tailwind template pack
]
# Set the allowed packs and the default pack
CRISPY_ALLOWED_TEMPLATE_PACKS = "tailwind"
CRISPY_TEMPLATE_PACK = "tailwind"

# forms.py and templates are used exactly the same way as with the
# standard django-crispy-forms example (#48). The output HTML will
# now have Tailwind classes (e.g., `class="block w-full ..."`).

Asynchronous & Task Queues

These libraries help you run code outside of the normal request-response cycle, handle long-running tasks, and support modern protocols like WebSockets.

56. Celery

What it is

The most popular distributed task queue for Python. It allows you to run time-consuming tasks asynchronously in the background.

Why it's used

When a user action triggers a long process (like sending an email or processing a video), you don't want the user to wait for it to finish. You use Celery to offload that task to a separate "worker" process. The view can immediately return a response to the user while the task runs in the background.

Core Concepts

  • Task: A function that you want to run asynchronously.
  • Worker: A separate process that listens for tasks and executes them.
  • Broker: A message queue (like RabbitMQ or Redis) that sits between your Django app and your workers.

Simple Example

# myapp/tasks.py
from celery import shared_task
import time

@shared_task
def send_confirmation_email(user_id):
    # Pretend this is a slow email sending process
    print(f"Sending email to user {user_id}...")
    time.sleep(10)
    print("Email sent!")
    return f"Email sent to user {user_id}."

# views.py
from .tasks import send_confirmation_email

def register_user(request):
    # ... create user object ...
    user_id = user.id
    # Offload the email task to a Celery worker.
    # .delay() is the magic here. It returns immediately.
    send_confirmation_email.delay(user_id)
    return HttpResponse("Registration successful! Check your email.")

57. Django Channels

What it is

[span_0]

A library that extends Django's capabilities beyond the standard HTTP request-response cycle to handle other protocols, most notably WebSockets.[span_0]

Why it's used

It allows you to build real-time applications, like chat apps, live notifications, or collaborative editing tools. With WebSockets, the server can push data to the client at any time, enabling instant updates without the client needing to constantly poll the server.

Core Concepts

  • ASGI: A new standard for Python web servers (like WSGI, but asynchronous) that Channels is built on.
  • Consumers: The equivalent of Django views for protocols like WebSockets. They handle events like connecting, disconnecting, and receiving messages.
  • Routing: Similar to urls.py, you define routes that map WebSocket connections to your Consumers.

Simple Example

A basic chat consumer.

# myapp/consumers.py
import json
from channels.generic.websocket import WebsocketConsumer

class ChatConsumer(WebsocketConsumer):
    def connect(self):
        self.accept() # Accept the WebSocket connection

    def disconnect(self, close_code):
        pass

    # Called when a message is received from the WebSocket
    def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        # Echo the message back to the sender
        self.send(text_data=json.dumps({
            'message': message
        }))

# myapp/routing.py
from django.urls import re_path
from . import consumers

websocket_urlpatterns = [
    re_path(r'ws/chat/$', consumers.ChatConsumer.as_asgi()),
]

58. django-celery-beat

What it is

A scheduler for Celery. [span_7]It allows you to run tasks on a periodic schedule (e.g., every 5 minutes, or every night at 2 AM).[span_7]

Why it's used

It's essential for recurring background jobs, like nightly data cleanup, fetching external data every hour, or sending out weekly summary emails. It stores the schedule in the Django database, so you can even manage scheduled tasks through the Django admin interface.

Core Concepts

  • Periodic Task: A task that is configured to run on a schedule.
  • Beat: A separate process (like a worker) that is responsible for triggering tasks when they are due.

Simple Example

# settings.py
# Tell Celery Beat to use the database scheduler
CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'

# You can also define a static schedule in your settings
CELERY_BEAT_SCHEDULE = {
    'cleanup-every-30-minutes': {
        'task': 'myapp.tasks.cleanup_old_sessions', # Path to your task
        'schedule': 1800.0, # Run every 1800 seconds (30 minutes)
        'args': (16, 16) # Optional arguments for the task
    },
}

# myapp/tasks.py
@shared_task
def cleanup_old_sessions(*args):
    print("Cleaning up old sessions...")
    # ... logic to delete old session data ...
    print("Cleanup complete.")

59. django-celery-results

What it is

A Celery result backend that uses the Django database or cache to store the results of your tasks.

Why it's used

When you run a task with Celery, you often want to know if it succeeded, what its return value was, or what error occurred if it failed. A result backend stores this information. This library makes it convenient to use your existing Django database for this purpose, and it lets you view task results in the Django admin.

Core Concepts

  • Result Backend: A storage system for task states and return values.

Simple Example

# settings.py
INSTALLED_APPS = [
    # ...
    'django_celery_results',
]
# Configure Celery to use the django-db backend
CELERY_RESULT_BACKEND = 'django-db'

# views.py
from .tasks import my_long_running_task

def start_task(request):
    # .delay() returns an AsyncResult object
    task_result = my_long_running_task.delay(10, 20)
    # You can store this task_id to check the status later
    return HttpResponse(f"Task started with ID: {task_result.id}")

def check_task_status(request, task_id):
    # Get the result object from the backend
    result = AsyncResult(task_id)
    if result.ready():
        return HttpResponse(f"Task finished! Result: {result.get()}")
    else:
        return HttpResponse(f"Task status: {result.state}")

60. Django-Q

What it is

A lightweight, integrated task queue for Django that is simpler to set up and use than Celery.

Why it's used

For many projects, Celery's complexity (requiring a separate broker like Redis) is overkill. Django-Q is a great alternative. It's easy to configure, can run in a single process for development, and can use the Django database as a broker, making setup trivial.

Core Concepts

  • async_task: The main function for dispatching a task.
  • Cluster: The python manage.py qcluster command starts the worker processes.

Simple Example

# settings.py
INSTALLED_APPS = ['django_q']
Q_CLUSTER = {
    'name': 'myproject',
    'workers': 4,
    'orm': 'default', # Use the default Django DB as the broker
}

# utils.py
def send_welcome_email(email):
    # A regular python function, no decorator needed
    print(f"Sending welcome email to {email}")
    # ... email logic ...

# views.py
from django_q.tasks import async_task
from .utils import send_welcome_email

def register(request):
    # ... create user ...
    async_task(send_welcome_email, user.email)
    return HttpResponse("Thanks for registering!")

61. Huey

What it is

A small, multi-threaded task queue for Python, often considered a lightweight alternative to Celery.

Why it's used

Huey shares the same goal as Django-Q: providing a simpler alternative to Celery. It's very easy to set up, supports Redis as a backend, and has a clean API. It supports task scheduling, retries, and periodic tasks, covering the most common use cases.

Core Concepts

  • Huey instance: You create an instance of the task queue.
  • @huey.task() decorator: Marks a function as a background task.

Simple Example

# tasks.py
from huey import RedisHuey
from huey.contrib.djhuey import task

# The huey instance is usually defined in a central place
# huey = RedisHuey('my-app')

@task() # This decorator comes from djhuey
def count_beans(num):
    print(f'-- counted {num} beans --')
    return num

# views.py
from .tasks import count_beans

def my_view(request):
    # Calling the function normally executes it immediately
    # count_beans(100)
    # Calling it with .delay() executes it in the background
    count_beans.delay(100)
    return HttpResponse("Task to count beans has been queued.")

62. Uvicorn

What it is

A lightning-fast ASGI (Asynchronous Server Gateway Interface) server, built on uvloop and httptools.

Why it's used

When you build an asynchronous Django application (using Django Channels or async views), you need an ASGI server to run it, not a WSGI server like Gunicorn. Uvicorn is one of the most popular and performant choices for running production ASGI applications.

Core Concepts

It's a command-line server application.

Simple Example

If your Django project is named myproject, Django creates an asgi.py file for you.

# To run your Django project with Uvicorn during development:
# uvicorn [django_project_name].asgi:application --reload

uvicorn myproject.asgi:application --reload

# In production, you would typically run Uvicorn behind a reverse proxy
# like Nginx and manage it with a process manager like systemd.
# It's often used with Gunicorn to manage worker processes:
# gunicorn myproject.asgi:application -w 4 -k uvicorn.workers.UvicornWorker

Testing

These libraries are crucial for writing automated tests to ensure your application is reliable, bug-free, and works as expected.

63. pytest-django

What it is

The essential plugin for using the powerful pytest testing framework with Django.

Why it's used

While Django's built-in TestCase is good, pytest offers a more modern, concise, and powerful way to write tests. It uses simple functions instead of classes, has a rich plugin ecosystem, and provides incredibly useful features like fixtures for managing test setup and teardown.

Core Concepts

  • Fixtures: Reusable functions (marked with @pytest.fixture) that set up test data or objects.
  • pytest-django provides built-in fixtures like db (for database access) and client (for making test requests).

Simple Example

# tests/test_views.py
import pytest
from django.urls import reverse
from myapp.models import Book

# The `db` fixture gives this test function access to the test database.
@pytest.mark.django_db
def test_book_list_view(client):
    # Create a book to test with
    Book.objects.create(title="Test Book", author="Test Author")
    url = reverse('book-list')
    response = client.get(url)

    assert response.status_code == 200
    assert "Test Book" in str(response.content)

# Note the lack of a class and `self`. It's just a clean function.

64. factory-boy

What it is

A fixtures replacement library that provides a powerful way to create instances of your models for testing.

Why it's used

Manually creating model instances in every test (Book.objects.create(...)) can be repetitive and fragile. factory-boy lets you define a "factory" for each model. This factory knows how to create a valid instance, often with realistic fake data. It makes your tests cleaner, more readable, and easier to maintain.

Core Concepts

  • Factory: A class that defines how to build an instance of a specific model.

Simple Example

# tests/factories.py
import factory
from myapp.models import Book
from faker import Faker # Often used with factory-boy

fake = Faker()

class BookFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Book

    # Define how to generate each field
    title = factory.Faker('catch_phrase')
    author = factory.Faker('name')

# tests/test_models.py
import pytest
from .factories import BookFactory

@pytest.mark.django_db
def test_book_creation():
    # Easily create a new book instance with realistic fake data
    book = BookFactory()
    assert book.pk is not None
    assert book.title != ""
    assert Book.objects.count() == 1

65. model-bakery

What it is

An alternative to fixtures and factory-boy for creating test objects.

Why it's used

Its main advantage is its simplicity and "smartness." You don't need to define a factory class for every model. model-bakery can inspect your model fields and automatically fill them with sensible, non-empty data. This is extremely fast for setting up simple test cases.

Core Concepts

  • baker.make(): The primary function to create one or more model instances.

Simple Example

# tests/test_models.py
import pytest
from model_bakery import baker
from myapp.models import Book

@pytest.mark.django_db
def test_book_creation_with_bakery():
    # No factory definition needed! Bakery figures it out.
    book = baker.make(Book)
    assert book.pk is not None
    assert book.title is not None and book.title != ""

    # You can also override specific fields
    specific_book = baker.make(Book, title="The Lord of the Rings")
    assert specific_book.title == "The Lord of the Rings"

    # And create multiple instances at once
    baker.make(Book, _quantity=5)
    assert Book.objects.count() == 6

66. coverage.py

What it is

A tool that measures the code coverage of your Python tests.

Why it's used

It tells you what percentage of your codebase (which lines, which branches) is actually executed by your tests. This helps you find untested parts of your application so you can write new tests to cover them. It's an essential metric for gauging the quality of your test suite.

Core Concepts

It's a command-line tool that you run your tests with.

Simple Example

# Instead of running `pytest`, you run it through `coverage`

# 1. Run your tests and collect coverage data
coverage run -m pytest

# 2. View a simple report in the terminal
coverage report

# Output might look like this:
# Name                Stmts   Miss  Cover
# ---------------------------------------
# myapp/models.py        10      0   100%
# myapp/views.py         25      5    80%  <- We need to test this more!
# ---------------------------------------
# TOTAL                  35      5    86%

# 3. Generate a detailed HTML report for Browse
coverage html

# This creates an `htmlcov/` directory. Open `index.html` in a browser.

67. freezegun

What it is

A library that lets you "freeze" time in your Python tests.

Why it's used

When you test code that depends on the current date or time (e.g., checking if a blog post is "recent" or if a token has expired), your tests can fail depending on when they are run. freezegun lets you set the "current" time to a fixed point, making your tests deterministic and reliable.

Core Concepts

  • @freeze_time decorator: A decorator you add to your test function to set the time.

Simple Example

# tests/test_models.py
import pytest
from datetime import date
from freezegun import freeze_time
from myapp.models import Article

@freeze_time("2025-07-21")
def test_is_published_today():
    # Inside this test, date.today() will ALWAYS be July 21, 2025
    article = Article.objects.create(publish_date=date.today())
    assert article.is_published_today() == True

@freeze_time("2025-07-20")
def test_is_not_published_today():
    article = Article.objects.create(publish_date=date(2025, 7, 21))
    # Here, today is July 20th, so the article is from the future
    assert article.is_published_today() == False

68. django-test-plus

What it is

A library that provides useful additions and assertions for Django's default TestCase.

Why it's used

It provides convenient shortcuts for common testing patterns, making your tests cleaner and more readable. For example, instead of writing multiple asserts to check a response, you can use self.assertGoodView().

Core Concepts

It provides a TestCase class (from test_plus.test) that you inherit from.

Simple Example

# tests/test_views.py
from test_plus.test import TestCase

class MyViewTests(TestCase):
    def test_home_page(self):
        # Instead of manually getting the URL and checking status_code...
        # response = self.client.get(reverse('home'))
        # self.assertEqual(response.status_code, 200)

        # ...you can do this:
        self.assertGoodView('home')

    def test_login_required_view(self):
        # Easily test that a view redirects to login if not authenticated
        self.assertLoginRequired('secret-page')

69. VCR.py

What it is

A library that records HTTP interactions your tests make and then "replays" them on future runs.

Why it's used

If your tests make requests to external APIs (e.g., a payment gateway or a weather service), they become slow, unreliable (the API could be down), and dependent on an internet connection. VCR.py records the API's response into a file (a "cassette") the first time you run the test. On subsequent runs, it uses the saved response from the file instead of making a real HTTP request, making your tests fast and deterministic.

Core Concepts

  • Cassette: A YAML file that stores the recorded HTTP request and response.

Simple Example

# tests/test_api_client.py
import pytest
import vcr
from myapp.api_client import get_weather

# The decorator tells VCR.py to record/replay this test's interactions
@vcr.use_cassette('tests/cassettes/weather.yaml')
def test_get_weather():
    # The first time this runs, it will make a REAL HTTP request.
    # It will save the response to weather.yaml.
    # All future runs will use the data from weather.yaml instead.
    weather_data = get_weather(city="London")
    assert weather_data['city'] == 'London'
    assert 'temperature' in weather_data

70. responses

What it is

A utility library for mocking out the requests library.

Why it's used

It's an alternative to VCR.py for testing code that makes HTTP requests. Instead of recording real responses, responses lets you explicitly define what fake response should be returned for a specific URL. This gives you more control and is great for testing specific error conditions (like a 500 or 404 error from an API).

Core Concepts

You add a mocked response for a specific URL and HTTP method.

Simple Example

# tests/test_api_client.py
import pytest
import responses
from myapp.api_client import get_user_data

# The pytest fixture automatically activates and deactivates the mock
@responses.activate
def test_get_user_data():
    # Define the fake response for a specific URL
    responses.add(
        responses.GET,
        'https://api.example.com/users/1',
        json={'error': 'Not Found'},
        status=404
    )

    # Your code will now receive this mocked response instead of making a real request
    user_data = get_user_data(user_id=1)
    assert user_data is None

71. Playwright

What it is

A modern library from Microsoft for reliable end-to-end (E2E) browser automation and testing.

Why it's used

For testing the full user journey in a real browser. It can launch a browser (Chromium, Firefox, WebKit), navigate to your site, click buttons, fill out forms, and assert that the page content is correct. This is the ultimate way to ensure your frontend and backend are working together correctly. pytest-playwright is the plugin to integrate it with pytest.

Core Concepts

  • Browser Automation: Scripting actions within a real web browser.

Simple Example

Using pytest-playwright.

# tests/test_e2e.py
import pytest
from playwright.sync_api import Page, expect

def test_homepage_has_correct_title(page: Page, live_server):
    # `page` is a fixture from pytest-playwright that controls the browser.
    # `live_server` is a fixture from pytest-django that runs your dev server.
    page.goto(live_server.url)

    # Use Playwright's locators and assertions
    # Check that the <h1> tag contains the text "Welcome"
    heading = page.get_by_role("heading", name="Welcome")
    expect(heading).to_be_visible()

    # Check the page title
    expect(page).to_have_title("My Awesome Site")

Static & Media Files

These libraries help you manage static files (CSS, JS) and user-uploaded media files (images, documents).

72. Pillow

What it is

The friendly fork of the Python Imaging Library (PIL). It's the de facto library for opening, manipulating, and saving many different image file formats in Python.

Why it's used

Django's ImageField requires Pillow to be installed. It uses Pillow behind the scenes to verify that an uploaded file is a valid image and to get its dimensions (height and width).

Core Concepts

It's a foundational dependency. You rarely use it directly in Django code, but it must be installed for ImageField to work.

Simple Example

# You just need to install it:
# pip install Pillow

# models.py
from django.db import models

class Profile(models.Model):
    # This field will not work unless Pillow is installed.
    # Django uses it to get the height and width automatically.
    avatar = models.ImageField(
        upload_to='avatars/',
        height_field='avatar_height',
        width_field='avatar_width'
    )
    avatar_height = models.PositiveIntegerField(null=True, blank=True)
    avatar_width = models.PositiveIntegerField(null=True, blank=True)

73. Whitenoise

What it is

A library that radically simplifies serving static files for Python web apps.

Why it's used

In production, serving static files directly from Django is inefficient. The standard approach is to use a dedicated web server like Nginx. Whitenoise offers a much simpler solution: it allows your Django application to serve its own static files efficiently, with proper caching and compression, making deployment on platforms like Heroku incredibly easy.

Core Concepts

It's a middleware that intercepts requests for static files and serves them directly.

Simple Example

# settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    # Whitenoise middleware should be placed right after the security middleware
    'whitenoise.middleware.WhiteNoiseMiddleware',
    # ... other middleware
]

# Use Whitenoise's storage backend for optimal performance (compression and caching)
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

# That's it! After running `collectstatic`, your Django app in production
# will now serve its own static files efficiently.

74. django-storages

What it is

A collection of custom storage backends for Django.

Why it's used

It allows you to store your user-uploaded media files (and optionally your static files) on remote cloud services like Amazon S3, Google Cloud Storage, or Azure Storage instead of on your web server's filesystem. This is essential for scalability, reliability, and for platforms where the local filesystem is ephemeral (like Heroku or AWS Lambda).

Core Concepts

  • Storage Backend: A class that Django uses to handle file operations (saving, opening, deleting).

Simple Example

Using Amazon S3 (requires boto3).

# settings.py
# pip install django-storages boto3

# Set the default storage for media files
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
# Optional: Set storage for static files as well
# STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

# S3 settings
AWS_ACCESS_KEY_ID = 'YOUR_AWS_ACCESS_KEY'
AWS_SECRET_ACCESS_KEY = 'YOUR_AWS_SECRET_KEY'
AWS_STORAGE_BUCKET_NAME = 'your-s3-bucket-name'
AWS_S3_REGION_NAME = 'us-east-1' # Example region

# Now, when you save a model with a FileField or ImageField,
# the file will be automatically uploaded to your S3 bucket.

75. Boto3

What it is

The official AWS (Amazon Web Services) SDK for Python.

Why it's used

It's the library that allows your Python application to interact with AWS services like S3 (for file storage), SQS (for message queues), SES (for email), and many others. In the context of Django, it's most commonly used as a dependency for django-storages to handle S3 uploads.

Core Concepts

It provides a low-level API to all AWS services.

Simple Example

While django-storages uses it under the hood, you can also use it directly.

# A script to list objects in an S3 bucket
import boto3

# Assuming credentials are configured (e.g., via environment variables)
s3 = boto3.client('s3')

response = s3.list_objects_v2(Bucket='your-s3-bucket-name')

if 'Contents' in response:
    for item in response['Contents']:
        print(f"- {item['Key']}")

76. sorl-thumbnail

What it is

A powerful and flexible library for generating image thumbnails in Django.

Why it's used

When users upload large images, you need to display smaller versions (thumbnails) on your site to save bandwidth and improve load times. sorl-thumbnail provides a simple template tag that generates these thumbnails on the fly, caches them, and handles various processing options like cropping and resizing.

Core Concepts

  • {% thumbnail %} tag: The template tag used to generate the image thumbnail.

Simple Example

# my_template.html
<!-- {% load thumbnail %} -->

<!-- {% thumbnail profile.avatar "100x100" crop="center" as im %} -->
    <img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}">
<!-- {% endthumbnail %} -->

# The first time this template is rendered, sorl will create a 100x100 cropped
# thumbnail and save it. All future requests will use the cached version.

77. easy-thumbnails

What it is

Another popular and simple library for creating image thumbnails in Django.

Why it's used

It's a strong alternative to sorl-thumbnail, offering a similar feature set with a slightly different API. It's known for being easy to set up and use, and it also provides a ThumbnailerImageField that can generate thumbnails automatically upon upload.

Core Concepts

  • {% thumbnail %} tag: Very similar to sorl's tag.
  • ThumbnailerAlias: Pre-defined thumbnail options (size, quality) that you can reference by name.

Simple Example

# settings.py
THUMBNAIL_ALIASES = {
    '': {
        'avatar': {'size': (50, 50), 'crop': True},
        'large': {'size': (800, 600)},
    },
}

# my_template.html
<!-- {% load thumbnail %} -->

<!-- {% thumbnail photo.image 'avatar' as im %} -->
    <img src="{{ im.url }}">
<!-- {% endthumbnail %} -->

# <img src="{{ photo.image|thumbnail_url:'large' }}">

Security

These libraries help you secure your Django application from common web vulnerabilities.

78. django-cors-headers

What it is

A library that handles the server headers required for Cross-Origin Resource Sharing (CORS).

Why it's used

By default, browsers block web pages from making JavaScript requests to a different domain (the "same-origin policy"). If your Django API is on api.example.com and your frontend is on app.example.com, you need to configure CORS headers to allow the frontend to communicate with the API. This library makes that easy.

Core Concepts

It's a middleware that adds the necessary Access-Control-Allow-Origin headers to your responses.

Simple Example

# settings.py
INSTALLED_APPS = [
    # ...
    'corsheaders',
]
MIDDLEWARE = [
    # CORS middleware should be placed as high as possible,
    # especially before any middleware that can generate responses.
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    # ...
]
# Define which origins are allowed to make cross-site requests
CORS_ALLOWED_ORIGINS = [
    "https://app.example.com",
    "http://localhost:3000", # for local frontend development
]
# Or, to allow all sites (less secure, use with caution)
# CORS_ALLOW_ALL_ORIGINS = True

79. django-csp

What it is

Middleware for adding Content Security Policy (CSP) headers to your application's responses.

Why it's used

CSP is a powerful security feature that helps prevent Cross-Site Scripting (XSS) attacks. You tell the browser which domains are trusted sources for loading scripts, styles, images, etc. If an attacker injects a malicious script from an untrusted domain, the browser will block it from running.

Core Concepts

It's a middleware that adds the Content-Security-Policy HTTP header.

Simple Example

# settings.py
MIDDLEWARE = [
    # ...
    'csp.middleware.CSPMiddleware',
    # ...
]
# A basic policy: only allow resources from the same domain
CSP_DEFAULT_SRC = ("'self'",)
# A more realistic policy: allow self, a specific CDN, and Google Fonts
CSP_SCRIPT_SRC = ("'self'", "https://cdn.example.com")
CSP_STYLE_SRC = ("'self'", "https://fonts.googleapis.com")
CSP_FONT_SRC = ("'self'", "https://fonts.gstatic.com")

80. Bleach

What it is

A whitelist-based HTML sanitizing library.

Why it's used

When you allow users to submit content with HTML (e.g., in a rich text editor), you must "sanitize" it before displaying it to other users. Bleach strips out all dangerous or unknown HTML tags and attributes (like <script> or onclick) while keeping a "whitelist" of safe tags (like <b>, <i>, <p>). This is another critical defense against XSS attacks.

Core Concepts

You provide a list of allowed tags and attributes, and Bleach removes everything else.

Simple Example

# views.py
import bleach
from .models import Comment

def post_comment(request):
    # The raw, potentially dangerous content from a user
    user_content = request.POST.get('comment_text')

    # Define the tags and attributes you want to allow
    allowed_tags = ['p', 'b', 'i', 'em', 'strong', 'a']
    allowed_attrs = {'a': ['href', 'title']}

    # Sanitize the content before saving it to the database
    safe_content = bleach.clean(
        user_content,
        tags=allowed_tags,
        attributes=allowed_attrs
    )
    Comment.objects.create(content=safe_content, user=request.user)
    # ...

81. argon2-cffi

What it is

A library that provides bindings for the Argon2 password hashing algorithm, a winner of the Password Hashing Competition.

Why it's used

It's widely considered the most secure and recommended password hashing algorithm available today. It is designed to be resistant to both GPU cracking attacks and side-channel attacks. Django can use it as its default password hasher to provide state-of-the-art security for your users' passwords.

Core Concepts

It provides a password hasher that you configure in Django's settings.

Simple Example

# settings.py
# pip install argon2-cffi

# Set Argon2 as the default password hasher.
# The order matters: the first one is the default for new passwords.
# Django can still verify old passwords using the other hashers.
PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.Argon2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
]

# Now, when a user sets or changes their password, it will be hashed with Argon2.

82. django-ipware

What it is

A simple utility for retrieving a user's real IP address from a request.

Why it's used

Getting the correct IP address can be tricky. If your application is behind a reverse proxy or load balancer (which is common in production), the IP address on the request object (request.META['REMOTE_ADDR']) will be the proxy's IP, not the user's. django-ipware intelligently checks the correct HTTP headers (like X-Forwarded-For) to find the true client IP address.

Core Concepts

It provides a single function to get the best-matched client IP.

Simple Example

# views.py
from ipware import get_client_ip

def my_view(request):
    # Get the user's IP address and whether it was routable
    client_ip, is_routable = get_client_ip(request)

    if client_ip is None:
        # Unable to get an IP
        print("Could not determine client IP.")
    else:
        # Got an IP!
        print(f"Client IP: {client_ip}")
        # You could use this for logging, rate limiting, or location services.

General Utilities & Deployment

This is a broad category for tools that help with deployment, making HTTP requests, interacting with external services, and general development productivity.

83. Gunicorn

What it is

A robust, widely used, and production-ready WSGI HTTP server for UNIX.

Why it's used

Django's built-in runserver is only for development. For production, you need a proper application server. Gunicorn is one of the most popular choices. It runs your Django application as multiple worker processes, allowing it to handle concurrent requests efficiently and reliably. It's typically run behind a reverse proxy like Nginx.

Core Concepts

  • WSGI: The standard interface between Python web applications and web servers.
  • Worker Processes: Gunicorn spawns multiple copies of your application to handle many requests at once.

Simple Example

# To run your Django project (named 'myproject') with Gunicorn:
# gunicorn [django_project_name].wsgi:application

gunicorn myproject.wsgi:application --workers 4 --bind 0.0.0.0:8000

# --workers 4: Spawns 4 worker processes to handle requests.
# --bind 0.0.0.0:8000: Listens for requests on port 8000 on all network interfaces.

84. django-environ

What it is

A library that allows you to configure your Django application using environment variables, following the principles of the Twelve-Factor App.

Why it's used

It's bad practice to store sensitive information like database passwords or secret keys directly in your settings.py file and commit it to version control. django-environ lets you store these values in a .env file (which you don't commit) or in the server's actual environment. It provides utilities to read these variables and cast them to the correct Python type (e.g., boolean, integer, list).

Core Concepts

  • .env file: A text file to store environment variables for local development.

Simple Example

# .env file (in your project root, add to .gitignore)
SECRET_KEY=my-super-secret-key-that-is-not-in-git
DEBUG=True
DATABASE_URL=postgres://user:password@host:port/dbname

# settings.py
import environ
import os

# Initialize environ
env = environ.Env(
    # set casting, default value
    DEBUG=(bool, False)
)

# Assuming .env is in the same directory as manage.py
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))

# Read the variables
SECRET_KEY = env('SECRET_KEY')
DEBUG = env('DEBUG') # Will be cast to a boolean
DATABASES = {'default': env.db()} # Parses the DATABASE_URL

85. python-decouple

What it is

A library very similar to django-environ for separating settings from your code.

Why it's used

It serves the exact same purpose as django-environ: helping you follow Twelve-Factor App principles by moving configuration into the environment. It can read from .ini or .env files. Some developers prefer its slightly different API. The choice between this and django-environ is largely a matter of personal preference.

Core Concepts

It provides a config function to read variables.

Simple Example

# settings.ini file (or .env)
[settings]
SECRET_KEY=my-super-secret-key
DEBUG=True

# settings.py
from decouple import config

# Read the variables, providing a default for unset ones
SECRET_KEY = config('SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)
DATABASE_URL = config('DATABASE_URL')
# ...

86. Requests

What it is

The de facto standard library for making HTTP requests in Python. It's not a Django-specific library but is used in almost every Django project that needs to communicate with an external API.

Why it's used

Python's built-in urllib is cumbersome to use. Requests provides a beautiful, simple API for all kinds of HTTP requests (GET, POST, etc.), handling JSON, authentication, headers, and more with ease.

Core Concepts

requests.get(), requests.post(), etc.

Simple Example

# A function in your Django app to fetch data from an external API
import requests

def get_github_user_info(username):
    url = f"https://api.github.com/users/{username}"
    try:
        response = requests.get(url, timeout=5)
        # Raise an exception for bad status codes (4xx or 5xx)
        response.raise_for_status()
        # The .json() method decodes the JSON response into a Python dict
        return response.json()
    except requests.exceptions.RequestException as e:
        print(f"An error occurred: {e}")
        return None

87. django-anymail

What it is

A single Django email backend for multiple transactional email service providers (ESPs).

Why it's used

It provides a unified, clean interface for sending emails through services like SendGrid, Mailgun, Postmark, Amazon SES, and others. It lets you easily switch between providers without changing your code and gives you access to provider-specific features (like tagging or tracking) that Django's default email backend doesn't support.

Core Concepts

It replaces Django's EMAIL_BACKEND with its own.

Simple Example

Using Mailgun.

# settings.py
INSTALLED_APPS = [
    # ...
    "anymail",
]
# Set Anymail's backend
EMAIL_BACKEND = "anymail.backends.mailgun.EmailBackend"
# Configure the backend with your provider's credentials
ANYMAIL = {
    "MAILGUN_API_KEY": "YOUR_MAILGUN_API_KEY",
    "MAILGUN_SENDER_DOMAIN": "mg.example.com", # Your Mailgun sending domain
}

# Now, you can use Django's standard mail functions, and they will be
# sent through Mailgun with all the benefits.
from django.core.mail import send_mail
send_mail("Subject", "Message body", "from@example.com", ["to@example.com"])

88. WeasyPrint

What it is

A smart tool that turns web pages (HTML and CSS) into PDFs.

Why it's used

It's one of the best ways to generate PDFs in Django. You can create a standard Django template with all the power of modern CSS (including flexbox and grid), and WeasyPrint will render it into a high-quality PDF. This is perfect for generating invoices, reports, tickets, or any other kind of document.

Core Concepts

It's a rendering engine that converts styled HTML to PDF.

Simple Example

# views.py
from django.http import HttpResponse
from django.template.loader import render_to_string
from weasyprint import HTML

def generate_invoice_pdf(request, order_id):
    order = Order.objects.get(pk=order_id)
    # 1. Render a Django template to an HTML string
    html_string = render_to_string('invoices/invoice_template.html', {'order': order})

    # 2. Use WeasyPrint to create the PDF from the HTML string
    pdf_file = HTML(string=html_string).write_pdf()

    # 3. Return the PDF as an HTTP response
    response = HttpResponse(pdf_file, content_type='application/pdf')
    response['Content-Disposition'] = f'attachment; filename="invoice-{order_id}.pdf"'
    return response

89. ReportLab

What it is

A powerful, low-level library for programmatically creating PDF documents from scratch.

Why it's used

Unlike WeasyPrint, which converts from HTML, ReportLab lets you draw directly onto a PDF canvas. You have precise control over the position of every line, shape, and piece of text. This is useful for generating very complex, structured documents where an HTML/CSS layout approach might be too restrictive.

Core Concepts

You work with a "canvas" object and draw elements onto it using coordinates.

Simple Example

# A view to generate a simple PDF
from django.http import HttpResponse
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch

def generate_simple_pdf(request):
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="hello.pdf"'

    # Create the PDF object, using the response object as its "file."
    p = canvas.Canvas(response)

    # Draw things on the PDF. (0,0) is the bottom-left corner.
    p.drawString(1 * inch, 10 * inch, "Hello, ReportLab!")
    p.line(1 * inch, 9.8 * inch, 3 * inch, 9.8 * inch)

    # Close the PDF object cleanly.
    p.showPage()
    p.save()
    return response

90. openpyxl

What it is

[span_0]

A Python library for reading and writing Excel 2010 (xlsx/xlsm) files.[span_0]

Why it's used

It's the go-to library whenever you need your Django application to generate or parse Excel spreadsheets. This is a common requirement for features like "Export to Excel" for reports, or for importing data that business users provide in spreadsheet format.

Core Concepts

You work with Workbook, Worksheet, and Cell objects.

Simple Example

Generating a simple Excel report.

# views.py
from django.http import HttpResponse
from openpyxl import Workbook
from .models import Sale

def export_sales_to_excel(request):
    response = HttpResponse(
        content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    )
    response['Content-Disposition'] = 'attachment; filename=sales_report.xlsx'

    workbook = Workbook()
    worksheet = workbook.active
    worksheet.title = 'Sales Report'

    # Write headers
    worksheet.cell(row=1, column=1, value='Product')
    worksheet.cell(row=1, column=2, value='Amount')

    # Write data from the database
    sales = Sale.objects.all()
    for i, sale in enumerate(sales, start=2):
        worksheet.cell(row=i, column=1, value=sale.product.name)
        worksheet.cell(row=i, column=2, value=sale.amount)

    workbook.save(response)
    return response

91. Invoke

What it is

A Python task execution tool and library, similar to Make or Fabric.

Why it's used

It's excellent for scripting common administrative and deployment tasks for your project in pure Python. You can define tasks like deploy, test, or cleanup in a tasks.py file and run them easily from the command line (invoke deploy).

Core Concepts

You create a tasks.py file and define functions decorated with @task.

Simple Example

# tasks.py (in your project root)
from invoke import task

@task
def test(c):
    """Run the test suite."""
    print("Running tests...")
    c.run("pytest")

@task
def deploy(c):
    """Deploy the latest version of the code."""
    print("Deploying application...")
    test(c) # You can call other tasks
    c.run("git push heroku main")
    c.run("heroku run python manage.py migrate")

# Run the tasks from your terminal
# invoke test
# invoke deploy

92. django-braces

What it is

A collection of reusable, generic "mixin" classes for Django's class-based views (CBVs).

Why it's used

[span_7]

It provides common functionality that you often need in CBVs, like requiring a user to be logged in or have a specific permission.[span_7] While Django has added some of these natively over time (LoginRequiredMixin), django-braces still offers many useful mixins that help keep your views DRY (Don't Repeat Yourself).

Core Concepts

  • Mixin: A class that you can "mix in" to your view's inheritance chain to add specific behavior.

Simple Example

Requiring a user to be a superuser to access a view.

# views.py
from django.views.generic import TemplateView
from braces.views import SuperuserRequiredMixin

# The SuperuserRequiredMixin will check if the user is a superuser.
# If not, it will return a 403 Forbidden error.
# It must come BEFORE the main view class.
class AdminDashboardView(SuperuserRequiredMixin, TemplateView):
    template_name = "admin/dashboard.html"

# Other useful mixins include PermissionRequiredMixin, GroupRequiredMixin, etc.

93. shortuuid

What it is

A library that generates concise, unambiguous, and URL-safe unique IDs.

Why it's used

Standard UUIDs (e.g., c9e8ab22-2433-4f0f-8c34-2e924c4422f9) are long and contain confusing characters. shortuuid creates shorter IDs (e.g., vytxeLgL542d3sPNYdpS2C) that are easier to use in URLs or show to users. They are still guaranteed to be unique.

Core Concepts

It uses a different alphabet (base57) to encode the UUID.

Simple Example

# models.py
import shortuuid
from django.db import models

class ShareableLink(models.Model):
    # Use a shortuuid as the primary key
    id = models.CharField(
        primary_key=True,
        max_length=22,
        default=shortuuid.uuid,
        editable=False
    )
    url = models.URLField()

# Now when you create a new link, its ID will be a short, URL-safe string.
# >>> link = ShareableLink.objects.create(url="https://google.com")
# >>> link.id
# 'vytxeLgL542d3sPNYdpS2C' (example)

94. django-haystack

What it is

A library that provides modular search for Django. It acts as a common API layer over various full-text search engines.

Why it's used

Searching your database with Model.objects.filter(field__icontains="...") is very inefficient for large amounts of text. django-haystack lets you integrate powerful, dedicated search engines like Elasticsearch or Solr into your project. You define what data should be indexed, and Haystack handles the process of sending it to the search engine and provides a unified API for querying it.

Core Concepts

  • SearchIndex: A class where you define which fields of a model should be indexed and searchable.
  • Backend: The specific search engine you are using (e.g., Elasticsearch).

Simple Example

# myapp/search_indexes.py
from haystack import indexes
from .models import Note

class NoteIndex(indexes.SearchIndex, indexes.Indexable):
    # This is the main field that will be searched
    text = indexes.CharField(document=True, use_template=True)
    # You can also index other fields for filtering
    author = indexes.CharField(model_attr='author')

    def get_model(self):
        return Note

# templates/search/indexes/myapp/note_text.txt (the template for the `text` field)
# {{ object.title }}
# {{ object.content }}

# Now you can search using Haystack's API in a view:
# from haystack.query import SearchQuerySet
# results = SearchQuerySet().filter(content='django')

95. elasticsearch-dsl

What it is

A high-level Python library for writing and running queries against Elasticsearch.

Why it's used

While Haystack is a good abstraction, sometimes you need more direct control over the power of Elasticsearch. elasticsearch-dsl provides a Pythonic, object-oriented way to build complex Elasticsearch queries, aggregations, and mappings. It makes interacting with Elasticsearch feel much more natural than writing raw JSON queries.

Core Concepts

You build up Search objects by chaining methods together.

Simple Example

# A function to search your Elasticsearch index directly
from elasticsearch_dsl import Search
from elasticsearch_dsl.query import MultiMatch

def search_articles(query_string):
    s = Search(index="my-article-index") \
        .query(MultiMatch(query=query_string, fields=['title', 'content'])) \
        .extra(size=10) # Limit to 10 results

    # Add a filter
    s = s.filter('term', tags='python')

    # Execute the search
    response = s.execute()

    for hit in response:
        print(f"Title: {hit.title}, Score: {hit.meta.score}")

    return response

Content Management Systems (CMS)

These are large, full-featured applications that you integrate into your Django project to provide a user-friendly interface for non-technical users to manage website content.

96. Wagtail

What it is

A powerful and beloved open-source CMS focused on flexibility for developers and a great user experience for editors.

Why it's used

Wagtail is famous for its clean, intuitive interface and its "StreamField" feature, which allows editors to build up pages from a flexible sequence of different content blocks (headings, rich text, images, videos, etc.). It gives developers full control over the models and templates while providing a structured yet flexible editing experience.

Core Concepts

  • Pages: Content is structured as a tree of "Page" models that you define in your code.
  • StreamField: A super-flexible field for creating free-form page content.

Simple Example

The core idea is defining a Page model.

# models.py
from wagtail.models import Page
from wagtail.fields import RichTextField, StreamField
from wagtail import blocks

class BlogIndexPage(Page):
    # A standard Wagtail page for listing blog posts
    intro = RichTextField(blank=True)

class BlogPostPage(Page):
    # A page for an individual blog post
    author = models.CharField(max_length=255)
    date = models.DateField("Post date")
    # StreamField allows editors to mix and match content blocks
    body = StreamField([
        ('heading', blocks.CharBlock(form_classname="title")),
        ('paragraph', blocks.RichTextBlock()),
        ('image', blocks.ImageChooserBlock()),
    ], use_json_field=True)

# After creating these models, you get a powerful admin interface
# for creating and managing this content.

97. Django CMS

What it is

A highly extensible and developer-friendly CMS with a strong focus on frontend editing.

Why it's used

Its standout feature is its frontend, drag-and-drop editing interface. Editors can browse the live site and directly add, edit, and move around "plugins" (content blocks) on the page. It's very powerful for building sites where the visual layout is a key concern.

Core Concepts

  • Placeholders: Areas in your templates where editors can add content.
  • Plugins: Reusable content components (text, image, video, etc.) that can be added to placeholders.

Simple Example

You define placeholders in your templates.

# my_template.html
<!-- {% load cms_tags %} -->
<html>
<body>
    <header>
        <!-- {% placeholder "header" %} -->
    </header>
    <main>
        <!-- {% placeholder "content" %} -->
    </main>
</body>
</html>
# In the Django CMS admin, an editor can now go to a page using this
# template and add a "Text Plugin" to the "content" placeholder or an
# "Image Plugin" to the "header" placeholder via a frontend editing interface.

98. Mezzanine

What it is

A consistent and powerful CMS that provides a set of well-integrated apps, aiming to be more like a full "content management platform."

Why it's used

Mezzanine comes with many features built-in that are often add-ons in other systems, such as a blog, a gallery, forms, and integration with e-commerce (Cartridge). It provides a more "batteries-included" experience out of the box, similar to WordPress, but built on Django.

Core Concepts

It's an integrated suite of Django apps.

Simple Example

The "example" is the quick setup.

# Mezzanine provides a project template for fast setup.
django-admin startproject --template=https://github.com/stephenmcd/mezzanine-project-template/archive/master.zip my_mezzanine_project

# After running migrations and creating a user, you will have a fully
# functional site with a blog, pages, and a configurable admin interface
# that is simpler and more content-focused than the default Django admin.

99. django-ckeditor

What it is

A library that integrates the popular and powerful CKEditor rich text (WYSIWYG) editor into your Django project.

Why it's used

Django's default TextField is just a plain text area. When you need to give users formatting options (bold, italics, lists, headings, embedding images), you need a rich text editor. django-ckeditor makes it trivial to replace a TextField with a full-featured CKEditor widget in both your forms and the Django admin.

Core Concepts

It provides custom model and form fields.

Simple Example

# models.py
from django.db import models
from ckeditor.fields import RichTextField

class Post(models.Model):
    title = models.CharField(max_length=200)
    # Instead of models.TextField(), use RichTextField()
    content = RichTextField()

# In the Django admin, the `content` field for the Post model will
# now be rendered as a full CKEditor widget, allowing rich text editing.

100. django-rosetta

What it is

An application that simplifies the translation of your Django project's interface.

Why it's used

It provides a user-friendly, web-based interface for editing the .po translation files that Django's internationalization (i18n) framework uses. Instead of having to edit these plain text files by hand, translators can log into the Rosetta interface, see all the translatable strings, and enter their translations directly in their browser.

Core Concepts

It provides a web interface for editing Django's .po files.

Simple Example

# settings.py
INSTALLED_APPS = [
    # ...
    'rosetta',
]

# urls.py
urlpatterns = [
    # ...
    re_path(r'^rosetta/', include('rosetta.urls')),
]

# In your code, you would mark strings for translation as usual:
from django.utils.translation import gettext as _
def my_view(request):
    output = _("Welcome to my site.")
    return HttpResponse(output)

# After running `manage.py makemessages`, you can navigate to /rosetta/
# in your browser, log in as a staff user, and you will see an interface
# to translate "Welcome to my site." into other languages.