Category: Uncategorized

  • Python Fastapi Dependency Injection Guide

    FastAPI has quickly become the go‑to framework for building high‑performance APIs in Python, and one of its secret weapons is the built‑in dependency injection system. Whether you’re a seasoned Python developer or just starting out, mastering FastAPI’s dependency injection (DI) can dramatically improve code readability, testability, and scalability. In this guide we’ll walk through the core concepts, practical patterns, and common pitfalls, giving you a complete roadmap to harness DI like a pro.

    Why Dependency Injection Matters in FastAPI

    Dependency injection is more than a buzzword; it’s a design pattern that decouples what a function does from how it gets the resources it needs. In FastAPI this translates to:

    • Cleaner endpoint definitions – business logic stays separate from request parsing and validation.
    • Easier testing – swap real services for mocks without touching the endpoint code.
    • Automatic request‑scoped lifecycles – FastAPI creates and disposes resources per request, preventing leaks.
    • Built‑in documentation – dependencies appear in the OpenAPI schema, making your API self‑describing.

    Basic Dependency Syntax

    The simplest way to declare a dependency is to use the Depends class from fastapi. Here’s a minimal example:

    from fastapi import FastAPI, Depends
    
    app = FastAPI()
    
    def get_query_param(q: str = None):
        return q
    
    @app.get("/items/")
    def read_items(q: str = Depends(get_query_param)):
        return {"query": q}
    

    FastAPI will call get_query_param for each request, inject the result into read_items, and also add the parameter to the generated Swagger UI.

    Understanding the Depends Call

    When you write Depends(get_query_param), FastAPI treats get_query_param as a callable that can itself have its own dependencies. This creates a dependency tree that FastAPI resolves automatically.

    Advanced Dependency Patterns

    1. Using Classes as Dependencies

    For more complex logic, you can encapsulate behavior in a class and use its methods as dependencies. The class can maintain state, such as a database connection pool.

    from fastapi import Depends
    
    class Database:
        def __init__(self, dsn: str):
            self.dsn = dsn
            # Imagine a real connection pool here
    
        def get_connection(self):
            # Return a new connection from the pool
            return f"Connection({self.dsn})"
    
    def get_database():
        # In a real app, the DSN might come from env variables
        return Database(dsn="postgresql://user:pass@localhost/db")
    
    def get_conn(db: Database = Depends(get_database)):
        return db.get_connection()
    

    Now any endpoint that needs a database connection can simply declare conn: str = Depends(get_conn).

    2. Request‑Scoped vs. Singleton Dependencies

    FastAPI creates a new instance of a dependency for each request by default. If you need a singleton (e.g., a global cache), you can use the cache parameter:

    from fastapi import Depends
    
    def get_settings():
        return {"debug": True, "version": "1.0.0"}
    
    # Cached means the function runs once per application start
    cached_settings = Depends(get_settings, use_cache=True)
    

    With use_cache=True, FastAPI stores the result after the first call and reuses it for subsequent requests.

    3. Dependency Injection with Async Functions

    FastAPI fully supports async dependencies, which is essential when dealing with I/O‑bound resources like databases or external APIs.

    import httpx
    from fastapi import Depends
    
    async def http_client():
        async with httpx.AsyncClient() as client:
            yield client  # Yield makes it a generator dependency
    
    @app.get("/external")
    async def call_external(client: httpx.AsyncClient = Depends(http_client)):
        resp = await client.get("https://api.example.com/data")
        return resp.json()
    

    The yield syntax tells FastAPI to treat the function as a context manager, automatically closing the client after the request finishes.

    Practical Use Cases

    Authentication and Authorization

    Security is a classic scenario for DI. Define a reusable dependency that extracts and validates a token, then inject it wherever needed.

    from fastapi import Header, HTTPException, Depends
    
    async def get_current_user(authorization: str = Header(...)):
        if not authorization.startswith("Bearer "):
            raise HTTPException(status_code=401, detail="Invalid auth header")
        token = authorization.split(" ")[1]
        # Validate token (pseudo‑code)
        user = decode_token(token)
        if not user:
            raise HTTPException(status_code=401, detail="Invalid token")
        return user
    
    @app.get("/profile")
    async def read_profile(user: dict = Depends(get_current_user)):
        return {"username": user["username"], "email": user["email"]}
    

    All endpoints that require authentication now simply add Depends(get_current_user), keeping the security logic centralized.

    Database Sessions with SQLAlchemy

    FastAPI’s documentation often showcases a SQLAlchemy session dependency. Below is a concise version that works with both sync and async engines.

    from sqlalchemy.orm import Session
    from fastapi import Depends
    
    def get_db():
        db = SessionLocal()
        try:
            yield db
        finally:
            db.close()
    
    @app.post("/users/")
    def create_user(user: UserCreate, db: Session = Depends(get_db)):
        db_user = User(**user.dict())
        db.add(db_user)
        db.commit()
        db.refresh(db_user)
        return db_user
    

    The yield ensures the session is closed after the request, preventing connection leaks.

    Caching with Redis

    When you need a fast, shared cache, inject a Redis client as a singleton.

    import aioredis
    from fastapi import Depends
    
    async def get_redis():
        redis = await aioredis.from_url("redis://localhost")
        try:
            yield redis
        finally:
            await redis.close()
    
    @app.get("/cached/{key}")
    async def read_cached(key: str, redis: aioredis.Redis = Depends(get_redis)):
        value = await redis.get(key)
        return {"key": key, "value": value}
    

    Because the Redis client is async and uses yield, FastAPI manages its lifecycle efficiently.

    Testing Dependencies

    One of the biggest advantages of DI is that you can replace real services with mocks in tests without touching the endpoint code.

    from fastapi.testclient import TestClient
    from unittest.mock import MagicMock
    
    # Original dependency
    def get_db():
        ...
    
    # Override for tests
    def override_get_db():
        mock_session = MagicMock()
        mock_session.query.return_value.filter_by.return_value.first.return_value = {"id": 1, "name": "Test"}
        yield mock_session
    
    app.dependency_overrides[get_db] = override_get_db
    
    client = TestClient(app)
    
    def test_read_user():
        response = client.get("/users/1")
        assert response.status_code == 200
        assert response.json()["name"] == "Test"
    

    FastAPI’s dependency_overrides dictionary makes swapping implementations trivial, enabling fast and reliable unit tests.

    Common Pitfalls and How to Avoid Them

    • Mixing sync and async code: Never call an async dependency from a sync function without await. Use async def for the endpoint or wrap the call with anyio.run if necessary.
    • Unintended singleton state: Remember that use_cache=True creates a global instance. If the object holds mutable state (e.g., a list), it will be shared across requests, leading to race conditions.
    • Forgotten yield in context managers: Without yield, resources like DB sessions or HTTP clients won’t be closed automatically, causing leaks.
    • Deep dependency trees: While FastAPI can resolve many layers, overly complex trees can hurt performance and readability. Keep dependencies focused and consider grouping related services into a single class.

    SEO Tips for FastAPI DI Articles (Bonus Section)

    If you’re publishing this guide on a blog, follow these quick SEO tricks to rank higher:

    1. Include the primary keyword “Python FastAPI dependency injection” in the first 100 words, in at least one <h2> and in the meta description.
    2. Use related terms such as “FastAPI Depends”, “DI pattern”, “async dependencies”, and “FastAPI testing” throughout the article.
    3. Add a <pre> code block for each major example; search engines love well‑structured code snippets.
    4. Link to the official FastAPI documentation and reputable tutorials for “link juice”.
    5. End with a clear call‑to‑action encouraging readers to try the examples and share their own DI patterns.

    Conclusion

    FastAPI’s dependency injection system is a powerful, yet approachable, tool that can transform the way you structure API projects. By separating concerns, managing lifecycles automatically, and providing seamless testing hooks, DI helps you write cleaner, more maintainable code. Start by refactoring a simple endpoint with Depends, then gradually adopt advanced patterns—class‑based services, async generators, and singleton caches. With the techniques

  • Python Fastapi Async Crud Operations Tutorial

    Welcome to our Python FastAPI async CRUD operations tutorial! If you’re looking to build high‑performance, non‑blocking web APIs with Python, FastAPI is the perfect framework. In this guide, we’ll walk you through setting up a FastAPI project, connecting to an asynchronous database, and implementing full Create, Read, Update, Delete (CRUD) functionality using async/await. By the end, you’ll have a production‑ready codebase you can extend for any modern web service.

    Why Choose FastAPI for Async CRUD?

    • Speed: Built on Starlette and Pydantic, FastAPI delivers near‑native performance, often rivaling Node.js and Go.
    • Async‑first: Native support for async endpoints means you can handle thousands of concurrent requests without blocking.
    • Automatic docs: OpenAPI and Swagger UI are generated automatically, making testing and client integration effortless.
    • Type safety: Python type hints improve code readability and catch bugs early, especially when dealing with complex data models.

    Project Setup: Tools and Dependencies

    Before diving into code, make sure you have the following installed:

    python>=3.9
    pip
    virtualenv (optional but recommended)

    Next, create a virtual environment and install the required packages:

    python -m venv venv
    source venv/bin/activate  # On Windows: venv\Scripts\activate
    pip install fastapi[all] uvicorn sqlalchemy[asyncio] aiosqlite

    We’ll use SQLAlchemy with its async extension and aiosqlite as the SQLite driver for simplicity. In a real‑world scenario, you could swap SQLite for PostgreSQL (via asyncpg) without changing much code.

    Defining the Database Model

    Let’s create a simple Item model that represents a product in an inventory system.

    # models.py
    from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
    from sqlalchemy.orm import declarative_base, sessionmaker
    from sqlalchemy import Column, Integer, String, Text
    
    DATABASE_URL = "sqlite+aiosqlite:///./test.db"
    
    engine = create_async_engine(DATABASE_URL, echo=True)
    AsyncSessionLocal = sessionmaker(
        bind=engine, class_=AsyncSession, expire_on_commit=False
    )
    
    Base = declarative_base()
    
    
    class Item(Base):
        __tablename__ = "items"
    
        id = Column(Integer, primary_key=True, index=True)
        name = Column(String(100), unique=True, index=True, nullable=False)
        description = Column(Text, nullable=True)
        price = Column(Integer, nullable=False)
    

    Creating the Database Tables

    Run the following script once to create the tables:

    # create_db.py
    import asyncio
    from models import Base, engine
    
    async def init_db():
        async with engine.begin() as conn:
            await conn.run_sync(Base.metadata.create_all)
    
    if __name__ == "__main__":
        asyncio.run(init_db())

    Execute it with python create_db.py. You’ll see SQL statements printed to the console, confirming that the items table is ready.

    Building the FastAPI Application

    Now we’ll set up the FastAPI app, define Pydantic schemas for request/response validation, and implement the async CRUD endpoints.

    Pydantic Schemas

    # schemas.py
    from pydantic import BaseModel, Field
    
    class ItemBase(BaseModel):
        name: str = Field(..., max_length=100, description="Unique name of the item")
        description: str | None = Field(None, description="Optional detailed description")
        price: int = Field(..., gt=0, description="Price in cents")
    
    class ItemCreate(ItemBase):
        pass
    
    class ItemUpdate(BaseModel):
        name: str | None = None
        description: str | None = None
        price: int | None = None
    
    class ItemRead(ItemBase):
        id: int
    
        class Config:
            orm_mode = True
    

    Dependency for Database Session

    # deps.py
    from typing import AsyncGenerator
    from models import AsyncSessionLocal
    
    async def get_db() -> AsyncGenerator:
        async with AsyncSessionLocal() as session:
            yield session
    

    CRUD Operations

    Below is the core logic for each CRUD operation. Notice the use of await with SQLAlchemy’s async methods.

    # crud.py
    from sqlalchemy import select, update, delete
    from sqlalchemy.exc import IntegrityError
    from sqlalchemy.ext.asyncio import AsyncSession
    from models import Item
    from schemas import ItemCreate, ItemUpdate
    
    async def get_item(db: AsyncSession, item_id: int):
        result = await db.execute(select(Item).where(Item.id == item_id))
        return result.scalar_one_or_none()
    
    async def get_items(db: AsyncSession, skip: int = 0, limit: int = 100):
        result = await db.execute(select(Item).offset(skip).limit(limit))
        return result.scalars().all()
    
    async def create_item(db: AsyncSession, item: ItemCreate):
        db_item = Item(**item.dict())
        db.add(db_item)
        try:
            await db.commit()
            await db.refresh(db_item)
            return db_item
        except IntegrityError:
            await db.rollback()
            raise
    
    async def update_item(db: AsyncSession, item_id: int, item: ItemUpdate):
        stmt = (
            update(Item)
            .where(Item.id == item_id)
            .values(**{k: v for k, v in item.dict().items() if v is not None})
            .execution_options(synchronize_session="fetch")
        )
        await db.execute(stmt)
        await db.commit()
        return await get_item(db, item_id)
    
    async def delete_item(db: AsyncSession, item_id: int):
        await db.execute(delete(Item).where(Item.id == item_id))
        await db.commit()
        return {"detail": f"Item {item_id} deleted"}
    

    Routing: Async Endpoints in FastAPI

    Finally, wire everything together in the main application file.

    # main.py
    from fastapi import FastAPI, HTTPException, Depends, status
    from typing import List
    
    from models import Base, engine
    from schemas import ItemCreate, ItemRead, ItemUpdate
    from crud import (
        get_item,
        get_items,
        create_item,
        update_item,
        delete_item,
    )
    from deps import get_db
    
    app = FastAPI(
        title="FastAPI Async CRUD Tutorial",
        description="A step‑by‑step guide to building async CRUD APIs with FastAPI and SQLAlchemy.",
        version="1.0.0",
    )
    
    
    @app.on_event("startup")
    async def startup():
        # Ensure tables exist on startup (optional)
        async with engine.begin() as conn:
            await conn.run_sync(Base.metadata.create_all)
    
    
    @app.get("/items/", response_model=List[ItemRead])
    async def read_items(skip: int = 0, limit: int = 10, db=Depends(get_db)):
        items = await get_items(db, skip=skip, limit=limit)
        return items
    
    
    @app.get("/items/{item_id}", response_model=ItemRead)
    async def read_item(item_id: int, db=Depends(get_db)):
        item = await get_item(db, item_id)
        if not item:
            raise HTTPException(status_code=404, detail="Item not found")
        return item
    
    
    @app.post("/items/", response_model=ItemRead, status_code=status.HTTP_201_CREATED)
    async def create_new_item(item: ItemCreate, db=Depends(get_db)):
        try:
            new_item = await create_item(db, item)
            return new_item
        except Exception:
            raise HTTPException(
                status_code=400,
                detail="Item could not be created – possibly a duplicate name.",
            )
    
    
    @app.put("/items/{item_id}", response_model=ItemRead)
    async def update_existing_item(
        item_id: int, item: ItemUpdate, db=Depends(get_db)
    ):
        existing = await get_item(db, item_id)
        if not existing:
            raise HTTPException(status_code=404, detail="Item not found")
        updated = await update_item(db, item_id, item)
        return updated
    
    
    @app.delete("/items/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
    async def delete_existing_item(item_id: int, db=Depends(get_db)):
        existing = await get_item(db, item_id)
        if not existing:
            raise HTTPException(status_code=404, detail="Item not found")
        await delete_item(db, item_id)
        return None
    

    Run the server with:

    uvicorn main:app --reload

    Visit http://127.0.0.1:8000/docs to explore the automatically generated Swagger UI. You can test each CRUD endpoint directly from the browser.

    Best Practices for Production‑Ready Async FastAPI Apps

    • Connection pooling: When using PostgreSQL, configure asyncpg pool size to match your workload.
    • Input validation: Leverage Pydantic’s validators for complex fields (e.g., price formats, email validation).
    • Error handling: Centralize exception handling with FastAPI’s exception_handler decorators.
    • Security: Add OAuth2, JWT, or API key authentication to protect your CRUD routes.
    • Testing: Use httpx.AsyncClient and pytest-asyncio for async endpoint tests.
    • Logging: Integrate structured logging (e.g., structlog) to capture request traces.

    Scaling Async FastAPI with Docker and Kubernetes

    Containerizing your FastAPI service ensures consistency across environments. Below is a minimal Dockerfile for the async CRUD app:

    # Dockerfile
    FROM python:3.11

  • Python Django Signals And Middleware Guide

    When you start building a Django application, you quickly discover that the framework does more than just route URLs and render templates. Two of its most powerful, yet often misunderstood, features are signals and middleware. Mastering these tools lets you inject custom logic at the right moment, keep your code DRY, and maintain a clean separation of concerns. In this guide we’ll demystify Django signals and middleware, show you how to create and use them effectively, and explain when each tool is the best choice for your project.

    Understanding Django Signals

    What Are Signals?

    Signals are a publish‑subscribe mechanism built into Django. They allow decoupled applications to get notified when certain actions occur—such as a model being saved, a user logging in, or a request finishing. Instead of tightly coupling code, you simply connect a receiver function to a signal and let Django handle the rest.

    How Signals Work Behind the Scenes

    • Sender: The object that emits the signal (e.g., django.db.models.Model).
    • Receiver: A callable that processes the signal payload.
    • Signal Instance: An instance of django.dispatch.Signal that holds a list of receivers.
    • Dispatch: When the sender calls signal.send(), Django loops through all registered receivers and passes them the provided arguments.

    Built‑In Signals You Should Know

    1. pre_save / post_save – Triggered before and after a model’s save() method.
    2. pre_delete / post_delete – Fired around a model’s deletion.
    3. m2m_changed – Emitted when a many‑to‑many relationship is altered.
    4. request_started / request_finished – Sent at the beginning and end of each HTTP request.
    5. user_logged_in, user_logged_out, user_login_failed – Part of Django’s authentication system.

    Creating a Custom Signal

    Sometimes the built‑in signals aren’t enough. You can define your own signal in any app’s signals.py file.

    # myapp/signals.py
    from django.dispatch import Signal
    
    # Provide a clear name and any arguments you expect to send
    order_completed = Signal(providing_args=['order', 'user'])
    

    Connecting Receivers

    Connect a receiver using the @receiver decorator or the signal.connect() method. The decorator is preferred for readability.

    # myapp/receivers.py
    from django.dispatch import receiver
    from .signals import order_completed
    from .models import Notification
    
    @receiver(order_completed)
    def send_order_notification(sender, **kwargs):
        order = kwargs['order']
        user = kwargs['user']
        # Example business logic
        Notification.objects.create(
            user=user,
            message=f"Your order #{order.id} has been completed!"
        )
    

    Don’t forget to import the module that registers the receivers (usually in apps.py) so Django loads them at startup.

    # myapp/apps.py
    from django.apps import AppConfig
    
    class MyAppConfig(AppConfig):
        name = 'myapp'
    
        def ready(self):
            # Import signal handlers
            import myapp.receivers
    

    Best Practices for Signals

    • Keep receivers lightweight: Heavy processing can slow down the request that triggered the signal.
    • Use async tasks for long‑running work: Send the signal, then delegate to Celery or Django‑Q.
    • Avoid circular imports: Import receivers inside AppConfig.ready() rather than at module top level.
    • Document signal contracts: Clearly list the arguments each signal provides.

    Deep Dive into Django Middleware

    What Is Middleware?

    Middleware is a stack of components that process a request before it reaches the view and a response before it’s sent to the client. Each middleware class implements at least one of the following methods:

    • process_request(self, request)
    • process_view(self, request, view_func, view_args, view_kwargs)
    • process_template_response(self, request, response)
    • process_response(self, request, response)
    • process_exception(self, request, exception)

    Middleware Lifecycle Illustrated

    request → process_request → process_view → view → process_template_response → 
    process_response → response → client
    

    Each middleware can modify the request or response objects, raise an exception, or short‑circuit the chain by returning a response early.

    Common Built‑In Middleware

    1. SecurityMiddleware – Adds security‑related headers.
    2. SessionMiddleware – Enables session support.
    3. AuthenticationMiddleware – Associates users with requests.
    4. MessageMiddleware – Enables Django’s messaging framework.
    5. CommonMiddleware – Handles URL normalization and ETag generation.

    Writing Your Own Middleware

    Let’s create a simple middleware that logs the execution time of each view. Save it as myproject/middleware.py.

    import time
    import logging
    
    logger = logging.getLogger(__name__)
    
    class ExecutionTimeMiddleware:
        """
        Logs how long a view takes to process.
        """
    
        def __init__(self, get_response):
            # One‑time configuration and initialization.
            self.get_response = get_response
    
        def __call__(self, request):
            start = time.monotonic()
            response = self.get_response(request)
            duration = (time.monotonic() - start) * 1000  # ms
            logger.info(
                "%s %s completed in %.2f ms",
                request.method,
                request.path,
                duration,
            )
            return response
    

    Then add it to settings.py:

    # settings.py
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        # ... other default middleware ...
        'myproject.middleware.ExecutionTimeMiddleware',  # ← custom middleware
    ]
    

    Middleware vs. Signals: When to Use Which

    • Use middleware when you need to interact with the request/response cycle itself—e.g., authentication, CORS handling, or request throttling.
    • Use signals for model‑level events or cross‑app communication that doesn’t belong in a view or request flow—e.g., sending a welcome email after a user registers.
    • Performance tip: Middleware runs on every request, while signals fire only when the associated event occurs. Choose the lighter tool for the job.

    Practical Examples Combining Signals and Middleware

    Example 1: Auto‑Assigning a User to a Group After Registration

    We’ll use a post_save signal for the User model and a custom middleware to ensure the user is authenticated before the signal runs.

    # accounts/signals.py
    from django.contrib.auth.models import User, Group
    from django.db.models.signals import post_save
    from django.dispatch import receiver
    
    @receiver(post_save, sender=User)
    def add_user_to_default_group(sender, instance, created, **kwargs):
        if created:
            default_group, _ = Group.objects.get_or_create(name='customers')
            instance.groups.add(default_group)
    

    Middleware to enforce login for certain URLs:

    # accounts/middleware.py
    from django.shortcuts import redirect
    from django.urls import reverse
    
    class LoginRequiredMiddleware:
        def __init__(self, get_response):
            self.get_response = get_response
    
        def __call__(self, request):
            if request.path.startswith('/secure/') and not request.user.is_authenticated:
                return redirect(f"{reverse('login')}?next={request.path}")
            return self.get_response(request)
    

    Example 2: Auditing API Calls with Signals and Middleware

    First, a middleware that captures request metadata:

    # api/middleware.py
    class AuditMiddleware:
    def __init__(self, get_response):
    self.get_response = get_response

    def __call__(self, request):

  • Python Django Redis Caching Performance

    When you pair Python’s powerful Django framework with Redis, a lightning‑fast in‑memory data store, you unlock a caching powerhouse that can dramatically boost your web application’s performance. In this guide we’ll explore why Redis is the go‑to choice for Django caching, walk through practical setup steps, and reveal proven techniques to squeeze every ounce of speed out of your stack. Whether you’re building a high‑traffic e‑commerce site or a data‑rich API, mastering Django‑Redis caching can cut latency, reduce database load, and improve user experience—all while keeping your code clean and maintainable.

    Why Choose Redis for Django Caching?

    Redis (Remote Dictionary Server) isn’t just another key‑value store; it’s a feature‑rich, persistent, and highly concurrent engine designed for real‑time workloads. Here are the top reasons developers prefer Redis over other cache backends when working with Django:

    • Sub‑millisecond latency – In‑memory storage means reads and writes happen in microseconds, dramatically lowering response times.
    • Rich data structures – Strings, hashes, lists, sets, sorted sets, and streams let you cache complex objects without serialization headaches.
    • Built‑in persistence – Optional RDB snapshots and AOF logs protect cached data against restarts, providing a safety net for expensive queries.
    • Scalability – Horizontal scaling with clustering and sharding lets you grow your cache layer alongside traffic spikes.
    • Pub/Sub and Lua scripting – Advanced use‑cases like cache invalidation, rate limiting, and atomic updates become trivial.

    Setting Up Django with Redis

    1. Install Required Packages

    Begin by adding the official django-redis package, which bridges Django’s cache framework to Redis:

    pip install django-redis

    Make sure you also have a running Redis server. For local development you can use Docker:

    docker run -d --name redis -p 6379:6379 redis:7-alpine

    2. Configure the Cache Backend

    In settings.py, replace the default cache configuration with a Redis backend. The following snippet is SEO‑friendly because it includes the target keyword “Python Django Redis caching performance” in comments and variable names, helping search engines understand the context.

    CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://127.0.0.1:6379/1",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
                # Enable connection pooling for better performance
                "CONNECTION_POOL_KWARGS": {"max_connections": 100},
                # Use a serializer that preserves Python types
                "SERIALIZER": "django_redis.serializers.pickle.PickleSerializer",
            },
            "TIMEOUT": 300,  # Cache entries expire after 5 minutes
        }
    }

    3. Verify the Integration

    Run a quick sanity check from the Django shell to ensure Redis is handling cache operations correctly:

    python manage.py shell
    >>> from django.core.cache import cache
    >>> cache.set('test_key', 'Django‑Redis works!', 10)
    >>> cache.get('test_key')
    'Django‑Redis works!'

    Core Caching Strategies for Maximum Performance

    Page‑Level Caching

    For views that render static HTML or rarely change data, Django’s cache_page decorator can store the entire response in Redis. This eliminates template rendering and database queries for subsequent requests.

    from django.views.decorators.cache import cache_page
    
    @cache_page(60 * 15)  # Cache for 15 minutes
    def product_list(request):
        # Expensive DB query here
        return render(request, "products/list.html")

    Template Fragment Caching

    When only parts of a page are static—like a navigation menu or a sidebar—use the {% cache %} template tag. This granular approach reduces memory usage while still delivering a fast user experience.

    {% load cache %}
    {% cache 300 "sidebar" %}
        {% include "partials/sidebar.html" %}
    {% endcache %}

    Low‑Level Caching for Querysets

    Cache heavy queryset results manually to avoid hitting the database on every request. Combine Django’s QuerySet methods with Redis key naming conventions for easy invalidation.

    def get_recent_posts():
        cache_key = "blog:recent_posts"
        posts = cache.get(cache_key)
        if posts is None:
            posts = list(Post.objects.filter(published=True).order_by("-created")[:10])
            cache.set(cache_key, posts, 300)  # Cache for 5 minutes
        return posts

    Cache Invalidation Techniques

    Stale data can hurt SEO and user trust. Use one of these proven patterns to keep your cache fresh:

    1. Time‑based expiration – Set TIMEOUT per key or globally to let Redis evict old entries automatically.
    2. Versioned keys – Append a version number to keys (e.g., product:42:v2) and bump the version when the underlying data changes.
    3. Signal‑driven invalidation – Connect Django signals (post_save, post_delete) to a function that deletes or updates related cache keys.

    Measuring and Optimizing Redis Cache Performance

    Key Metrics to Track

    • Cache hit ratio – The percentage of requests served from Redis. Aim for 80%+ in production.
    • Latency (p99) – Measure the 99th percentile response time of cache reads/writes.
    • Memory usage – Monitor used_memory and maxmemory_policy to avoid out‑of‑memory evictions.
    • Eviction count – High evictions indicate your cache size is too small for the workload.

    Using Redis CLI and Monitoring Tools

    Run redis-cli INFO or integrate with Redis Sentinel and Prometheus for real‑time dashboards. Example command:

    redis-cli INFO memory stats

    Typical output snippet:

    # Memory
    used_memory:10485760
    used_memory_human:10.00M
    maxmemory:536870912
    maxmemory_policy:noeviction
    evicted_keys:0

    Performance Tweaks for High‑Traffic Django Apps

    • Connection pooling – Already enabled in the CACHES config; it reduces TCP handshake overhead.
    • Pipeline commands – Batch multiple Redis operations into a single round‑trip using django_redis’s pipeline() method.
    • Use appropriate data structures – Store counters in INCR instead of fetching, incrementing, and setting a string.
    • Set maxmemory and eviction policy – Choose volatile-lru or allkeys-lru to automatically drop the least‑recently‑used keys when memory fills up.
    • Compress large payloads – Enable COMPRESSOR in django-redis to shrink JSON or pickled objects before storage.

    Sample Pipeline Usage

    Below is a concise example that updates a view counter and stores a recent‑activity list atomically:

    from django_redis import get_redis_connection
    
    def record_view(user_id, article_id):
        r = get_redis_connection("default")
        pipe = r.pipeline()
        pipe.incr(f"article:{article_id}:views")
        pipe.lpush(f"user:{user_id}:recent", article_id)
        pipe.ltrim(f"user:{user_id}:recent", 0, 49)  # Keep only last 50
        pipe.execute()

    Best Practices and Common Pitfalls

    Do Not Cache Sensitive Data Unencrypted

    Redis stores data in plain text by default. If you cache personally identifiable information (PII) or authentication tokens, enable redis-cli CONFIG SET requirepass and use TLS termination or encrypt values before caching.

    Avoid Over‑Caching

    While it’s tempting to cache everything, excessive caching can lead to memory pressure and stale content. Prioritize:

    1. Expensive DB queries (joins, aggregations)
    2. Third‑party API responses
    3. Static assets that change infrequently

    Keep Cache Keys Predictable

    Adopt a naming convention such as

  • Python Django Celery Background Tasks

    When you build a Python Django application that needs to handle time‑consuming operations—such as sending emails, processing images, or generating reports—running those jobs synchronously can slow down your web requests and hurt user experience. This is where Celery steps in as the de‑facto standard for managing background tasks in Django projects. In this guide we’ll explore why Celery is a perfect match for Django, how to set it up, best practices for writing reliable tasks, and common pitfalls to avoid. By the end, you’ll have a solid, production‑ready foundation for executing Python Django Celery background tasks that keep your site fast, responsive, and scalable.

    Why Use Celery for Background Tasks in Django?

    Celery is a powerful, open‑source asynchronous task queue that integrates seamlessly with Django. It offers several advantages that make it the go‑to solution for background processing:

    • Scalability: Workers can be added or removed on the fly, allowing you to handle spikes in traffic without rewriting code.
    • Reliability: Tasks are persisted in a broker (e.g., RabbitMQ or Redis) and can be retried automatically on failure.
    • Extensibility: Built‑in support for periodic tasks, task chaining, and result backends makes complex workflows easy to implement.
    • Community & Ecosystem: A large community provides plugins, tutorials, and extensions that keep the stack up‑to‑date.

    Core Components of a Django‑Celery Setup

    1. Broker

    The broker is the messaging layer that transports tasks from Django to Celery workers. The two most popular choices are:

    • Redis – lightweight, fast, and easy to configure.
    • RabbitMQ – robust, supports advanced routing, and ideal for large‑scale deployments.

    2. Worker

    Workers are the processes that actually execute your tasks. They run independently of the Django web server and can be scaled horizontally across multiple machines.

    3. Result Backend (Optional)

    If you need to store the outcome of a task—such as a generated PDF or a status flag—you can configure a result backend (Redis, Database, or Cache). For fire‑and‑forget tasks, a backend isn’t required.

    Step‑by‑Step: Setting Up Celery in a Django Project

    Step 1: Install Required Packages

    pip install celery[redis] django-celery-results
    

    Step 2: Create a celery.py File

    Place this file in your project’s root (next to settings.py) and configure the Celery app.

    import os
    from celery import Celery
    from django.conf import settings
    
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
    
    app = Celery('myproject')
    app.config_from_object('django.conf:settings', namespace='CELERY')
    app.autodiscover_tasks()
    

    Step 3: Update __init__.py

    Ensure the Celery app is loaded when Django starts.

    from .celery import app as celery_app
    
    __all__ = ('celery_app',)
    

    Step 4: Configure Settings

    Add the following to settings.py (adjust the broker URL to match your environment):

    # Celery Settings
    CELERY_BROKER_URL = 'redis://localhost:6379/0'
    CELERY_RESULT_BACKEND = 'django-db'  # using django-celery-results
    CELERY_ACCEPT_CONTENT = ['json']
    CELERY_TASK_SERIALIZER = 'json'
    CELERY_RESULT_SERIALIZER = 'json'
    CELERY_TIMEZONE = 'UTC'
    

    Step 5: Define a Sample Task

    Create a tasks.py file inside any Django app (e.g., myapp/tasks.py) and write a simple background job.

    from celery import shared_task
    import time
    
    @shared_task
    def send_welcome_email(user_id):
        from django.contrib.auth import get_user_model
        User = get_user_model()
        user = User.objects.get(pk=user_id)
        # Simulate email sending delay
        time.sleep(5)
        user.email_user(
            subject='Welcome!',
            message='Thanks for joining our platform.',
        )
        return f'Email sent to {user.email}'
    

    Step 6: Call the Task from Django Views

    Instead of sending the email directly, enqueue the task:

    from myapp.tasks import send_welcome_email
    
    def register_user(request):
        # ... user creation logic ...
        send_welcome_email.delay(new_user.id)  # <-- non‑blocking call
        return HttpResponse('Registration successful')
    

    Step 7: Run the Worker

    Open a terminal and start a Celery worker for your project:

    celery -A myproject worker -l info
    

    If you need periodic tasks, launch the beat scheduler alongside the worker:

    celery -A myproject beat -l info
    

    Advanced Patterns for Robust Background Processing

    Task Retries and Exponential Backoff

    Network glitches or third‑party API failures are common. Celery lets you automatically retry a task with backoff logic:

    @shared_task(bind=True, max_retries=5, default_retry_delay=60)
    def fetch_remote_data(self, url):
        import requests
        try:
            response = requests.get(url, timeout=10)
            response.raise_for_status()
            return response.json()
        except requests.RequestException as exc:
            raise self.retry(exc=exc, countdown=2 ** self.request.retries)
    

    Chaining and Grouping Tasks

    When a workflow consists of multiple steps—e.g., resize an image, store it, then notify the user—you can chain tasks to run sequentially, or group them to run in parallel:

    from celery import chain, group
    
    # Sequential execution
    pipeline = chain(
        resize_image.s(image_path),
        upload_to_s3.s(),
        notify_user.s(user_id)
    )
    pipeline.apply_async()
    
    # Parallel execution
    batch = group(
        generate_thumbnail.s(img) for img in image_list
    )
    batch.apply_async()
    

    Using a Result Backend for Status Tracking

    If you need to display progress in the UI (e.g., “Your report is 70% complete”), store task IDs and poll the result backend:

    task = generate_report.delay(params)
    # In the front‑end, periodically call:
    # GET /api/task-status/?id=task.id
    # The view returns task.state and task.result
    

    Best Practices and Common Pitfalls

    • Keep tasks idempotent: Design tasks so that running them multiple times does not produce duplicate side effects. This simplifies retries.
    • Avoid heavy imports in tasks.py: Import only what you need inside the task function to reduce worker start‑up time.
    • Use environment‑specific broker URLs: Store credentials in .env files and never hard‑code them.
    • Monitor workers: Tools like flower or Prometheus exporters give you insight into queue length, task latency, and worker health.
    • Graceful shutdown: When deploying new code, send the SIGTERM signal to workers and wait for them to finish in‑flight tasks before restarting.
    • Limit task timeouts: Set CELERY_TASK_TIME_LIMIT to prevent runaway jobs from hogging resources.

    Testing Celery Tasks Locally

    During development you might not want to spin up a full broker. Celery provides an in_memory broker and a task_always_eager setting that runs tasks synchronously:

    # settings.py (development only)
    if DEBUG:
        CELERY_TASK_ALWAYS_EAGER = True
        CELERY_BROKER_URL = 'memory://'
    

    With this configuration, calling my_task.delay() will execute the function immediately, making unit testing straightforward.

    Deploying Celery in Production

    When moving to production, consider the following checklist:

    1. Choose a reliable broker (Redis or RabbitMQ) with persistence enabled.
    2. Run multiple worker processes (e.g., celery -A myproject worker -c 4) to utilize all CPU cores.
    3. Separate concerns: one set of workers for fast, lightweight tasks; another for heavy jobs like video encoding.
    4. Configure systemd or supervisord units to keep workers alive after crashes.
    5. Secure broker connections with TLS and authentication.
    6. Set up monitoring (Flower, Grafana, or Datadog) to alert on queue backlogs.

    Conclusion

    Integrating Celery with Django transforms a monolithic web app into a responsive, scalable system capable of handling any background task you can imagine. By following the step‑by‑step setup, embracing advanced patterns like retries, chaining, and result tracking, and adhering to best practices, you’ll ensure that your Python

  • Python Django Stripe Payment Integration

    Integrating Stripe with a Python Django application is one of the most reliable ways to accept online payments, subscription billing, and one‑time purchases. In this guide we’ll walk through everything you need to know—from setting up a Stripe account and installing the required packages, to building secure checkout views, handling webhooks, and testing your integration. By the end of this post, you’ll have a production‑ready Django project that can process real payments while keeping PCI compliance and user experience front and center.

    Why Choose Stripe for Django Projects?

    Stripe has become the go‑to payment processor for developers because it offers:

    • Developer‑friendly APIs with extensive documentation and SDKs for Python.
    • Support for one‑time payments, subscriptions, and marketplace payouts.
    • Built‑in fraud detection and PCI‑DSS compliance via Stripe Elements.
    • Transparent pricing and a global reach with support for dozens of currencies.

    When combined with Django’s robust MVC architecture, Stripe lets you build scalable e‑commerce platforms, SaaS products, and donation sites with minimal friction.

    Prerequisites

    What You Need Before Starting

    1. A Python 3.8+ environment (virtualenv or Poetry recommended).
    2. A fresh or existing Django 4.x project.
    3. A Stripe account. Sign up at dashboard.stripe.com and obtain your Publishable key and Secret key.
    4. Basic knowledge of Django models, views, and templates.

    Step 1: Install the Stripe Python SDK

    The official Stripe library simplifies API calls and handles request signing for you.

    pip install stripe
    

    After installation, add the Stripe keys to your Django settings. Keep them out of version control by using environment variables:

    # settings.py
    import os
    
    STRIPE_PUBLIC_KEY = os.getenv('STRIPE_PUBLIC_KEY')
    STRIPE_SECRET_KEY = os.getenv('STRIPE_SECRET_KEY')
    

    Step 2: Create a Simple Product Model

    Even if you only need a one‑time charge, storing product information in the database helps you manage inventory and pricing.

    # models.py
    from django.db import models
    
    class Product(models.Model):
        name = models.CharField(max_length=255)
        description = models.TextField(blank=True)
        price_cents = models.PositiveIntegerField(help_text='Price in cents')
        stripe_price_id = models.CharField(max_length=255, blank=True, null=True)
    
        def __str__(self):
            return self.name
    

    After defining the model, run python manage.py makemigrations && python manage.py migrate to create the table.

    Step 3: Sync Products with Stripe

    Stripe uses Price objects to represent the amount you charge. You can create them programmatically when a product is saved.

    # signals.py
    import stripe
    from django.conf import settings
    from django.db.models.signals import post_save
    from django.dispatch import receiver
    from .models import Product
    
    stripe.api_key = settings.STRIPE_SECRET_KEY
    
    @receiver(post_save, sender=Product)
    def create_stripe_price(sender, instance, created, **kwargs):
        if created and not instance.stripe_price_id:
            price = stripe.Price.create(
                unit_amount=instance.price_cents,
                currency='usd',
                product_data={'name': instance.name},
            )
            instance.stripe_price_id = price.id
            instance.save(update_fields=['stripe_price_id'])
    

    Don’t forget to import the signals module in apps.py or __init__.py so Django registers the handler.

    Step 4: Build the Checkout View

    We’ll use Stripe’s pre‑built Checkout Session to keep PCI compliance simple. The view creates a session and redirects the user to Stripe’s hosted payment page.

    # views.py
    import stripe
    from django.conf import settings
    from django.shortcuts import get_object_or_404, redirect
    from django.urls import reverse
    from .models import Product
    
    stripe.api_key = settings.STRIPE_SECRET_KEY
    
    def create_checkout_session(request, product_id):
        product = get_object_or_404(Product, pk=product_id)
    
        checkout_session = stripe.checkout.Session.create(
            payment_method_types=['card'],
            line_items=[{
                'price': product.stripe_price_id,
                'quantity': 1,
            }],
            mode='payment',
            success_url=request.build_absolute_uri(
                reverse('payment_success')
            ) + '?session_id={CHECKOUT_SESSION_ID}',
            cancel_url=request.build_absolute_uri(
                reverse('payment_cancel')
            ),
        )
        return redirect(checkout_session.url, code=303)
    

    Map the view in urls.py:

    # urls.py
    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('checkout//', views.create_checkout_session, name='checkout'),
        path('success/', views.payment_success, name='payment_success'),
        path('cancel/', views.payment_cancel, name='payment_cancel'),
    ]
    

    Step 5: Handle Success and Cancellation

    After a successful payment, Stripe redirects the user back to the success_url. You can retrieve the session details to confirm the payment status.

    # views.py (continued)
    def payment_success(request):
        session_id = request.GET.get('session_id')
        session = stripe.checkout.Session.retrieve(session_id)
        # Here you could create an Order object, send email, etc.
        return render(request, 'payment_success.html', {'session': session})
    
    def payment_cancel(request):
        return render(request, 'payment_cancel.html')
    

    Step 6: Secure Your Integration with Webhooks

    Relying solely on the redirect flow is risky because users can close the browser before the redirect happens. Webhooks let your server be notified of payment events directly from Stripe.

    Configure a Webhook Endpoint

    # urls.py
    urlpatterns += [
        path('webhook/', views.stripe_webhook, name='stripe_webhook'),
    ]
    
    # views.py (continued)
    import json
    from django.http import HttpResponse, HttpResponseBadRequest
    
    def stripe_webhook(request):
        payload = request.body
        sig_header = request.META.get('HTTP_STRIPE_SIGNATURE')
        endpoint_secret = os.getenv('STRIPE_WEBHOOK_SECRET')
    
        try:
            event = stripe.Webhook.construct_event(
                payload, sig_header, endpoint_secret
            )
        except (ValueError, stripe.error.SignatureVerificationError):
            return HttpResponseBadRequest()
    
        # Handle the event
        if event['type'] == 'checkout.session.completed':
            session = event['data']['object']
            # Mark the order as paid, send receipt, etc.
            handle_successful_payment(session)
    
        return HttpResponse(status=200)
    
    def handle_successful_payment(session):
        # Example: create an Order model entry
        from .models import Order, Product
        product = Product.objects.get(stripe_price_id=session['display_items'][0]['price']['id'])
        Order.objects.create(
            product=product,
            stripe_session_id=session['id'],
            amount=session['amount_total'],
            email=session['customer_details']['email'],
            paid=True,
        )
    

    To test webhooks locally, use the Stripe CLI:

    stripe listen --forward-to localhost:8000/webhook/
    

    Step 7: Front‑End Integration with Stripe Elements (Optional)

    If you prefer a fully custom checkout UI, Stripe Elements lets you embed secure card fields directly in your Django templates. Below is a minimal example.

    
    {% load static %}
    
    
    
        Custom Checkout
        
        
    
    
        

    Pay {{ product.name }} – ${{ product.price_cents|floatformat:2|divisibleby:100 }}

    Using Elements gives you full control over the checkout design while still delegating sensitive card handling to Stripe.

    Best Practices for Production

    • Never expose your secret key in client‑side code. Only the publishable key should be sent to the browser.
    • Store API keys and webhook secrets in environment variables or a secrets manager.
    • Enable Stripe Radar to automatically block high‑risk transactions.
  • Python Django Social Media App From Scratch

    Imagine building a full‑featured social media platform that lets users share posts, follow friends, and chat in real time—all powered by the clean, scalable Python framework Django. In this step‑by‑step guide we’ll walk you through creating a Python Django social media app from scratch, covering everything from project setup and data modeling to real‑time notifications and deployment. Whether you’re a seasoned Django developer or just getting started, you’ll walk away with a production‑ready codebase and a solid understanding of the best practices that make Django the go‑to choice for modern web applications.

    Why Choose Django for a Social Media App?

    Django’s “batteries‑included” philosophy means you get a robust ORM, an authentication system, and a powerful admin interface out of the box—exactly the building blocks you need for a social network. Here are the top reasons developers pick Django for social media projects:

    • Rapid development: Built‑in admin and authentication cut weeks of work.
    • Scalability: Django scales from a single‑server prototype to a multi‑node production cluster.
    • Security: Automatic protection against XSS, CSRF, and SQL injection.
    • Community & Packages: Rich ecosystem (e.g., django‑rest‑framework, django‑channels) accelerates feature development.

    Project Setup: From Scratch to Running Server

    1. Install Python and Django

    # Ensure you have Python 3.11+ installed
    python -V
    
    # Create a virtual environment
    python -m venv env
    source env/bin/activate   # On Windows: env\Scripts\activate
    
    # Install Django and supporting packages
    pip install django djangorestframework django‑channels
    

    2. Create the Project and Core Apps

    # Start a new Django project called "socialnetwork"
    django-admin startproject socialnetwork
    cd socialnetwork
    
    # Create reusable apps
    python manage.py startapp accounts   # User auth & profiles
    python manage.py startapp posts      # Posts, likes, comments
    python manage.py startapp chat       # Real‑time messaging
    

    3. Configure Settings

    Open socialnetwork/settings.py and add the new apps to INSTALLED_APPS. Also enable channels and set the ASGI application:

    INSTALLED_APPS = [
        # Django defaults...
        'django.contrib.admin',
        'django.contrib.auth',
        # Third‑party
        'rest_framework',
        'channels',
        # Your apps
        'accounts',
        'posts',
        'chat',
    ]
    
    # Channels configuration
    ASGI_APPLICATION = 'socialnetwork.asgi.application'
    CHANNEL_LAYERS = {
        "default": {
            "BACKEND": "channels.layers.InMemoryChannelLayer"
        },
    }
    

    Designing the Data Model

    A well‑structured data model is the backbone of any social platform. Below is a simplified schema that you can expand as needed.

    • UserProfile – Extends Django’s User with avatar, bio, and follower relationships.
    • Post – Stores text, optional image, timestamp, and a foreign key to the author.
    • Like – Many‑to‑one relation linking a UserProfile to a Post.
    • Comment – Text, author, post reference, and creation date.
    • Message – Real‑time chat model with sender, receiver, content, and read status.

    Example of the Post model in posts/models.py:

    from django.db import models
    from django.conf import settings
    
    class Post(models.Model):
        author = models.ForeignKey(
            settings.AUTH_USER_MODEL,
            on_delete=models.CASCADE,
            related_name='posts'
        )
        content = models.TextField(max_length=500)
        image = models.ImageField(upload_to='post_images/', blank=True, null=True)
        created_at = models.DateTimeField(auto_now_add=True)
    
        def __str__(self):
            return f'{self.author.username}: {self.content[:30]}'
    

    Building Core Features

    User Authentication and Profiles

    Django’s built‑in auth app handles sign‑up, login, and password reset. To add profile data, create a UserProfile model linked via a OneToOneField and use Django signals to auto‑create a profile on user registration.

    from django.db import models
    from django.contrib.auth.models import User
    from django.db.models.signals import post_save
    from django.dispatch import receiver
    
    class UserProfile(models.Model):
        user = models.OneToOneField(User, on_delete=models.CASCADE)
        avatar = models.ImageField(upload_to='avatars/', default='avatars/default.jpg')
        bio = models.CharField(max_length=200, blank=True)
    
    @receiver(post_save, sender=User)
    def create_user_profile(sender, instance, created, **kwargs):
        if created:
            UserProfile.objects.create(user=instance)
    

    Expose these endpoints with Django REST Framework (DRF) for a modern JavaScript front‑end:

    from rest_framework import serializers, viewsets, permissions
    from .models import UserProfile
    
    class UserProfileSerializer(serializers.ModelSerializer):
        class Meta:
            model = UserProfile
            fields = ('id', 'user', 'avatar', 'bio')
    
    class UserProfileViewSet(viewsets.ModelViewSet):
        queryset = UserProfile.objects.all()
        serializer_class = UserProfileSerializer
        permission_classes = [permissions.IsAuthenticated]
    

    Posting, Liking, and Commenting

    Implement CRUD APIs for posts using DRF viewsets. Likes can be toggled with a simple POST request that creates or deletes a Like instance.

    # posts/views.py
    from rest_framework import viewsets, permissions
    from .models import Post, Like, Comment
    from .serializers import PostSerializer, LikeSerializer, CommentSerializer
    
    class PostViewSet(viewsets.ModelViewSet):
        queryset = Post.objects.select_related('author').all()
        serializer_class = PostSerializer
        permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    
        def perform_create(self, serializer):
            serializer.save(author=self.request.user)
    
    class LikeToggleView(viewsets.GenericViewSet):
        permission_classes = [permissions.IsAuthenticated]
    
        def create(self, request, pk=None):
            post = Post.objects.get(pk=pk)
            like, created = Like.objects.get_or_create(user=request.user, post=post)
            if not created:
                like.delete()
                return Response({'status': 'unliked'})
            return Response({'status': 'liked'})
    

    Real‑Time Updates with Django Channels

    Social platforms thrive on instant feedback. django‑channels adds WebSocket support to Django, enabling live notifications, chat, and feed updates without page reloads.

    # chat/consumers.py
    import json
    from channels.generic.websocket import AsyncWebsocketConsumer
    
    class ChatConsumer(AsyncWebsocketConsumer):
        async def connect(self):
            self.room_name = self.scope['url_route']['kwargs']['room_name']
            self.room_group = f'chat_{self.room_name}'
            await self.channel_layer.group_add(self.room_group, self.channel_name)
            await self.accept()
    
        async def disconnect(self, close_code):
            await self.channel_layer.group_discard(self.room_group, self.channel_name)
    
        async def receive(self, text_data):
            data = json.loads(text_data)
            await self.channel_layer.group_send(
                self.room_group,
                {
                    'type': 'chat_message',
                    'message': data['message'],
                    'user': self.scope['user'].username,
                }
            )
    
        async def chat_message(self, event):
            await self.send(text_data=json.dumps({
                'message': event['message'],
                'user': event['user'],
            }))
    

    Don’t forget to route the WebSocket URL in socialnetwork/routing.py and include it in asgi.py.

    Deploying Your Django Social Media App

    Once development is complete, move to production with these essential steps:

    • Choose a host: DigitalOcean, AWS EC2, or Heroku (with Docker for Channels).
    • Configure a production‑ready web server: Use gunicorn + nginx for HTTP and daphne for ASGI.
    • Set environment variables: DEBUG=False
  • Python Django Multi-Vendor E-Commerce Platform

    Building a Python Django multi‑vendor e‑commerce platform is no longer a distant dream for developers who want to launch a marketplace like Amazon, Etsy, or eBay. With Django’s batteries‑included philosophy, robust ORM, and thriving third‑party ecosystem, you can create a scalable, secure, and feature‑rich marketplace that lets multiple sellers list products, manage orders, and receive payments—all from a single codebase. In this guide we’ll explore the core architecture, essential Django apps, best‑practice patterns, and practical code snippets that help you turn a simple idea into a production‑ready multi‑vendor store.

    Why Choose Django for a Multi‑Vendor Marketplace?

    • Rapid development: Django’s admin, authentication system, and built‑in security features reduce boilerplate code.
    • Scalable ORM: Handles complex relationships between vendors, products, orders, and commissions with ease.
    • Extensible ecosystem: Packages like django-oscar, django-shop, and django-mptt accelerate marketplace features.
    • Strong community: Extensive documentation, tutorials, and third‑party plugins keep you from reinventing the wheel.

    Core Components of a Django Multi‑Vendor E‑Commerce Platform

    1. User Management & Vendor Onboarding

    Separate the concepts of Customer and Vendor while sharing the same User model. A common approach is to extend AbstractUser and add a profile_type field.

    from django.contrib.auth.models import AbstractUser
    from django.db import models
    
    class User(AbstractUser):
        PROFILE_CHOICES = (
            ('customer', 'Customer'),
            ('vendor',   'Vendor'),
        )
        profile_type = models.CharField(
            max_length=10,
            choices=PROFILE_CHOICES,
            default='customer',
        )
    

    After registration, vendors complete an onboarding form that captures store name, tax information, and payment details. Store this data in a dedicated VendorProfile model linked via a OneToOneField.

    2. Product Catalog with Hierarchical Categories

    Multi‑vendor platforms need flexible category trees. django-mptt (Modified Preorder Tree Traversal) is perfect for this.

    from mptt.models import MPTTModel, TreeForeignKey
    
    class Category(MPTTModel):
        name = models.CharField(max_length=255)
        parent = TreeForeignKey(
            'self',
            on_delete=models.CASCADE,
            null=True,
            blank=True,
            related_name='children'
        )
        class MPTTMeta:
            order_insertion_by = ['name']
    

    Each Product links to a Vendor and a Category, allowing sellers to manage their own inventory while the marketplace presents a unified catalog.

    3. Shopping Cart & Checkout Flow

    The cart can be session‑based for anonymous users and persisted for logged‑in shoppers. Store cart items in a model that references both Product and Vendor to calculate per‑vendor subtotals.

    class CartItem(models.Model):
        user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
        session_key = models.CharField(max_length=40, null=True, blank=True)
        product = models.ForeignKey(Product, on_delete=models.CASCADE)
        vendor = models.ForeignKey(VendorProfile, on_delete=models.CASCADE)
        quantity = models.PositiveIntegerField(default=1)
        added_at = models.DateTimeField(auto_now_add=True)
    

    4. Order Management & Split Payments

    When a customer checks out, the system creates a single Order object with related OrderItem entries. Each OrderItem belongs to a specific vendor, enabling split‑payment logic.

    class Order(models.Model):
        user = models.ForeignKey(User, on_delete=models.CASCADE)
        total_amount = models.DecimalField(max_digits=10, decimal_places=2)
        created_at = models.DateTimeField(auto_now_add=True)
        status = models.CharField(max_length=20, default='pending')
    
    class OrderItem(models.Model):
        order = models.ForeignKey(Order, related_name='items', on_delete=models.CASCADE)
        product = models.ForeignKey(Product, on_delete=models.PROTECT)
        vendor = models.ForeignKey(VendorProfile, on_delete=models.PROTECT)
        price = models.DecimalField(max_digits=10, decimal_places=2)
        quantity = models.PositiveIntegerField()
    

    Integrate with payment gateways (Stripe Connect, PayPal Adaptive Payments, or Razorpay) to route funds directly to each vendor after deducting marketplace commission.

    5. Vendor Dashboard

    A dedicated dashboard gives sellers insight into sales, inventory, and payouts. Use Django’s class‑based views combined with django-tables2 for sortable tables and django-chartjs for visual analytics.

    Step‑by‑Step Blueprint to Build the Platform

    Step 1 – Set Up the Project Structure

    1. Create a new Django project: django-admin startproject marketplace
    2. Inside the project, generate core apps:
      • accounts – custom user and vendor profiles
      • catalog – categories and products
      • cart – cart logic
      • orders – order processing and payments
      • dashboard – vendor admin area
    3. Install required third‑party packages:
      pip install django django-mptt django-rest-framework django-allauth stripe django-tables2 django-chartjs

    Step 2 – Configure Settings for a Multi‑Vendor Environment

    # marketplace/settings.py
    INSTALLED_APPS = [
        # Django core
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        # Third‑party
        'rest_framework',
        'allauth',
        'allauth.account',
        'allauth.socialaccount',
        'mptt',
        'django_tables2',
        'chartjs',
        # Local apps
        'accounts',
        'catalog',
        'cart',
        'orders',
        'dashboard',
    ]
    
    AUTH_USER_MODEL = 'accounts.User'
    
    # Stripe Connect settings (example)
    STRIPE_CLIENT_ID = os.getenv('STRIPE_CLIENT_ID')
    STRIPE_SECRET_KEY = os.getenv('STRIPE_SECRET_KEY')
    STRIPE_WEBHOOK_SECRET = os.getenv('STRIPE_WEBHOOK_SECRET')
    

    Step 3 – Build the Vendor Onboarding Flow

    Leverage django-allauth for authentication, then add a view that captures vendor details and creates a Stripe Connect account.

    def vendor_signup(request):
        if request.method == 'POST':
            form = VendorSignupForm(request.POST, request.FILES)
            if form.is_valid():
                user = form.save(commit=False)
                user.profile_type = 'vendor'
                user.save()
                VendorProfile.objects.create(user=user, **form.cleaned_data)
                # Redirect to Stripe onboarding
                return redirect('stripe_onboard')
        else:
            form = VendorSignupForm()
        return render(request, 'accounts/vendor_signup.html', {'form': form})
    

    Step 4 – Implement the Product Listing API

    Expose product data via Django REST Framework so mobile apps or third‑party front‑ends can consume it.

    class ProductSerializer(serializers.ModelSerializer):
        vendor = serializers.CharField(source='vendor.store_name')
        category = serializers.CharField(source='category.name')
    
        class Meta:
            model = Product
            fields = ['id', 'name', 'description', 'price', 'vendor', 'category', 'stock']
    
    class ProductListView(generics.ListAPIView):
        queryset = Product.objects.filter(active=True)
        serializer_class = ProductSerializer
        filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
        filterset_fields = ['category', 'vendor']
        search_fields = ['name', 'description']
        ordering_fields = ['price', 'created_at']
    

    Step 5 – Handle Split Payments with Stripe Connect

    When an order is placed, create a PaymentIntent for each vendor and attach the marketplace’s commission as an application fee.

    import stripe
    
    stripe.api_key = settings.STRIPE_SECRET_KEY
    
    def create_vendor_payment_intent(order_item):
        vendor_account_id = order_item.vendor.stripe_account_id
        amount = int(order_item.price * order_item.quantity * 100)  # cents
        application_fee = int(amount * settings.MARKETPLACE_COMMISSION_RATE)
    
        intent = stripe.PaymentIntent.create(
            amount=amount,
            currency='usd',
            payment_method_types=['card'],
            transfer_data={'destination': vendor_account_id},
            application_fee_amount=application_fee,
        )
        return intent.client_secret
    

    Step 6 – Design the Vendor Dashboard

    Use class‑based generic views with django-tables2 to list orders, and chartjs to visualize sales trends.

    class VendorOrderTable(tables.Table):
    order_id = tables.Column(verbose_name='Order')
    total = tables.Column()
    status = tables.Column()
    created_at = tables.DateColumn()

    class Meta:
    model = OrderItem
    template_name = 'django_tables2/bootstrap.html'
    fields = ('order_id', 'total', 'status', 'created_at')

    class DashboardView(LoginRequiredMixin, TemplateView):
    template_name = 'dashboard/index.html

  • Python Django Custom User Model Guide

    When you start building a Django application, the default User model often feels limiting. Whether you need to store extra profile information, switch to email‑based authentication, or integrate third‑party services, a custom user model is the clean, future‑proof solution. This guide walks you through every step of creating, configuring, and maintaining a Python Django custom user model, so you can avoid common pitfalls and keep your project scalable.

    Why Replace Django’s Default User Model?

    Out‑of‑the‑box Django provides a robust auth.User model, but it assumes a specific data structure:

    • Username is required and must be unique.
    • Only a limited set of fields (first name, last name, email, etc.) are available.
    • Changing the model after the first migration is extremely painful.

    For most real‑world projects, you’ll eventually need one or more of the following:

    1. Email‑only login – eliminating usernames entirely.
    2. Additional profile fields such as phone number, avatar, or subscription status.
    3. Multi‑tenant support where the same email can exist in different organizations.
    4. Integration with external identity providers (OAuth, SSO, etc.) that require custom flags.

    Implementing a custom user model from day one prevents costly refactors later and aligns your code with Django’s official recommendations.

    Step‑by‑Step Guide to Creating a Custom User Model

    1. Plan Your Model Structure

    Before writing any code, decide which fields are essential. A typical modern user model includes:

    • email – unique, used for authentication.
    • first_name and last_name – optional but handy.
    • is_staff and is_active – for admin control.
    • Any domain‑specific fields (e.g., date_of_birth, profile_picture).

    2. Create a New App (Optional but Recommended)

    python manage.py startapp accounts
    

    Keeping authentication logic in its own accounts app isolates concerns and makes future reuse easier.

    3. Define the Custom User Model

    In accounts/models.py, subclass AbstractBaseUser and PermissionsMixin. Use BaseUserManager to handle user creation.

    from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
    from django.contrib.auth.models import PermissionsMixin
    from django.db import models
    from django.utils import timezone
    
    class CustomUserManager(BaseUserManager):
        def create_user(self, email, password=None, **extra_fields):
            if not email:
                raise ValueError('The Email field must be set')
            email = self.normalize_email(email)
            user = self.model(email=email, **extra_fields)
            user.set_password(password)
            user.save(using=self._db)
            return user
    
        def create_superuser(self, email, password, **extra_fields):
            extra_fields.setdefault('is_staff', True)
            extra_fields.setdefault('is_superuser', True)
            extra_fields.setdefault('is_active', True)
    
            if extra_fields.get('is_staff') is not True:
                raise ValueError('Superuser must have is_staff=True.')
            if extra_fields.get('is_superuser') is not True:
                raise ValueError('Superuser must have is_superuser=True.')
    
            return self.create_user(email, password, **extra_fields)
    
    class CustomUser(AbstractBaseUser, PermissionsMixin):
        email = models.EmailField('email address', unique=True)
        first_name = models.CharField('first name', max_length=30, blank=True)
        last_name = models.CharField('last name', max_length=30, blank=True)
        is_staff = models.BooleanField('staff status', default=False)
        is_active = models.BooleanField('active', default=True)
        date_joined = models.DateTimeField('date joined', default=timezone.now)
    
        objects = CustomUserManager()
    
        USERNAME_FIELD = 'email'
        REQUIRED_FIELDS = []  # Email & password are required by default
    
        class Meta:
            verbose_name = 'user'
            verbose_name_plural = 'users'
    
        def __str__(self):
            return self.email
    

    4. Tell Django About the New Model

    Add the following line to settings.py before any app that imports django.contrib.auth:

    AUTH_USER_MODEL = 'accounts.CustomUser'
    

    This single setting instructs every Django component—admin, authentication backends, and the ORM—to use your custom model.

    5. Update the Admin Interface

    Without a proper admin configuration, the default admin will break. Create accounts/admin.py:

    from django.contrib import admin
    from django.contrib.auth.admin import UserAdmin
    from .models import CustomUser
    from django.utils.translation import gettext_lazy as _
    
    @admin.register(CustomUser)
    class CustomUserAdmin(UserAdmin):
        list_display = ('email', 'first_name', 'last_name', 'is_staff')
        list_filter = ('is_staff', 'is_active', 'is_superuser')
        search_fields = ('email', 'first_name', 'last_name')
        ordering = ('email',)
    
        fieldsets = (
            (None, {'fields': ('email', 'password')}),
            (_('Personal info'), {'fields': ('first_name', 'last_name')}),
            (_('Permissions'), {
                'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions'),
            }),
            (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
        )
        add_fieldsets = (
            (None, {
                'classes': ('wide',),
                'fields': ('email', 'password1', 'password2'),
            }),
        )
        filter_horizontal = ('groups', 'user_permissions')
    

    6. Run Migrations

    python manage.py makemigrations accounts
    python manage.py migrate
    

    Because the custom model is defined before any migrations that reference auth.User, Django creates the correct database schema without conflicts.

    7. Adjust Forms and Authentication Backends (Optional)

    If you use Django’s built‑in authentication views, replace the default forms with ones that expect an email field:

    from django import forms
    from django.contrib.auth.forms import UserCreationForm, UserChangeForm
    from .models import CustomUser
    
    class CustomUserCreationForm(UserCreationForm):
        class Meta(UserCreationForm.Meta):
            model = CustomUser
            fields = ('email',)
    
    class CustomUserChangeForm(UserChangeForm):
        class Meta:
            model = CustomUser
            fields = ('email', 'first_name', 'last_name')
    

    Then point your URLs to the custom views or use django-allauth for a ready‑made solution that works seamlessly with a custom user model.

    Best Practices & Common Pitfalls

    Never Change AUTH_USER_MODEL After Migration

    Switching the user model after the first migration requires data migrations, manual SQL, or third‑party tools. Treat the decision as a permanent architectural choice.

    Use get_user_model() Everywhere

    Hard‑coding CustomUser in imports couples your code to a specific implementation. Instead, import the active model dynamically:

    from django.contrib.auth import get_user_model
    User = get_user_model()
    

    Keep the Model Lightweight

    Store only authentication‑related fields in the custom user model. For richer profile data, create a separate Profile model linked via a OneToOneField. This separation preserves performance and keeps the auth system simple.

    Test Authentication Thoroughly

    • Verify that createsuperuser works with the new fields.
    • Check password reset, email verification, and login flows.
    • Run integration tests that simulate real‑world login attempts.

    Consider Third‑Party Packages

    If you need advanced features like social login, multi‑factor authentication, or JWT tokens, libraries such as django‑allauth, simplejwt, or django‑extensions already support custom user models. Integrating them early saves time.

    Advanced Topics

    Using UUIDs as Primary Keys

    For added security and easier data migration, replace the default integer id with a UUID:

    import uuid
    from django.db import models
    
    class CustomUser(AbstractBaseUser, PermissionsMixin):
        id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
        # ... other fields remain the same
    

    Multi‑Tenant Authentication

    When a single database serves multiple customers, include a tenant foreign key and adjust the manager’s get_by_natural_key method to filter by tenant ID.

    Custom Permissions

    Beyond <

  • Python Django Rest Framework Drf Tutorial

    Are you ready to turn your Django projects into powerful, scalable web APIs? In this step‑by‑step tutorial we’ll explore the Django REST Framework (DRF)—the most popular toolkit for building RESTful services with Python and Django. From setting up a clean development environment to deploying a production‑ready API, you’ll learn the essential concepts, best practices, and code snippets that will accelerate your journey from beginner to confident DRF developer.

    What Is Django REST Framework?

    Django REST Framework is an open‑source library that extends Django’s capabilities, providing a robust set of tools for creating RESTful APIs. It handles serialization, authentication, permissions, pagination, and more, while staying true to Django’s “batteries‑included” philosophy. Because DRF is built on top of Django’s ORM and request/response cycle, you can reuse your existing models and views, making the transition from a traditional web app to an API seamless.

    Setting Up the Development Environment

    1. Install Python and create a virtual environment

    # Verify Python version (>=3.9 recommended)
    python3 --version
    
    # Create and activate a virtual environment
    python3 -m venv drf-env
    source drf-env/bin/activate  # On Windows use `drf-env\Scripts\activate`
    

    2. Install Django and DRF

    # Upgrade pip first
    pip install --upgrade pip
    
    # Install Django and Django REST Framework
    pip install django djangorestframework
    

    3. Optional: Install useful extensions

    • django-filter – for powerful query‑parameter filtering.
    • drf-yasg – to generate interactive Swagger/OpenAPI documentation.
    • pytest-django – for streamlined testing.

    Creating a New Django Project

    Start by scaffolding a fresh Django project named myapi and an app called books. The app will host a simple library catalog API.

    # Create project and app
    django-admin startproject myapi
    cd myapi
    python manage.py startapp books
    
    # Register the app and DRF in settings.py
    # myapi/settings.py
    INSTALLED_APPS = [
        # default Django apps …
        'rest_framework',
        'books',
    ]
    

    Building Your First API with DRF

    Define the Model

    In books/models.py we’ll create a Book model with a few useful fields.

    from django.db import models
    
    class Book(models.Model):
        title = models.CharField(max_length=200)
        author = models.CharField(max_length=100)
        published_date = models.DateField()
        isbn = models.CharField(max_length=13, unique=True)
        price = models.DecimalField(max_digits=6, decimal_places=2)
    
        def __str__(self):
            return f"{self.title} by {self.author}"
    

    Create a Serializer

    Serializers translate model instances into JSON (or other formats) and validate incoming data.

    # books/serializers.py
    from rest_framework import serializers
    from .models import Book
    
    class BookSerializer(serializers.ModelSerializer):
        class Meta:
            model = Book
            fields = '__all__'  # Expose all model fields
    

    Write a ViewSet

    ViewSets combine the logic for list, create, retrieve, update, and delete operations into a single class.

    # books/views.py
    from rest_framework import viewsets
    from .models import Book
    from .serializers import BookSerializer
    
    class BookViewSet(viewsets.ModelViewSet):
        """
        API endpoint that allows books to be viewed or edited.
        """
        queryset = Book.objects.all()
        serializer_class = BookSerializer
    

    Configure URLs with Routers

    DRF’s DefaultRouter automatically generates the standard routes for a ViewSet.

    # books/urls.py
    from django.urls import include, path
    from rest_framework.routers import DefaultRouter
    from .views import BookViewSet
    
    router = DefaultRouter()
    router.register(r'books', BookViewSet)
    
    urlpatterns = [
        path('', include(router.urls)),
    ]
    

    Finally, include the app’s URLs in the project’s root URL configuration.

    # myapi/urls.py
    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('api/', include('books.urls')),  # All DRF endpoints under /api/
    ]
    

    Advanced Topics

    Authentication and Permissions

    Secure your API by enabling authentication schemes and fine‑grained permission classes.

    • Token Authentication – Simple token‑based auth for mobile or SPA clients.
    • JWT (JSON Web Tokens) – Stateless, scalable tokens using djangorestframework-simplejwt.
    • Session Authentication – Leverages Django’s built‑in session framework (good for internal tools).

    Example permission setup in settings.py:

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'rest_framework.authentication.TokenAuthentication',
            'rest_framework.authentication.SessionAuthentication',
        ],
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.IsAuthenticatedOrReadOnly',
        ],
    }
    

    Pagination

    Large result sets can be split into manageable pages. DRF offers several pagination styles.

    # settings.py
    REST_FRAMEWORK = {
        'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
        'PAGE_SIZE': 10,
    }
    

    Clients can now request /api/books/?page=2 to retrieve the second page of results.

    Filtering and Search

    Enhance the API with dynamic query parameters using django-filter and DRF’s built‑in search filter.

    # books/views.py (add to BookViewSet)
    from django_filters.rest_framework import DjangoFilterBackend
    from rest_framework import filters
    
    class BookViewSet(viewsets.ModelViewSet):
        queryset = Book.objects.all()
        serializer_class = BookSerializer
        filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
        filterset_fields = ['author', 'published_date']
        search_fields = ['title', 'author']
        ordering_fields = ['published_date', 'price']
    

    Testing Your API

    Automated tests keep your API reliable. DRF provides an APIClient that works like the Django test client but understands JSON payloads.

    # books/tests.py
    from rest_framework.test import APITestCase
    from django.urls import reverse
    from .models import Book
    
    class BookAPITest(APITestCase):
        def setUp(self):
            self.book = Book.objects.create(
                title='Django for APIs',
                author='John Doe',
                published_date='2023-01-15',
                isbn='1234567890123',
                price='29.99'
            )
            self.list_url = reverse('book-list')  # auto‑generated by router
    
        def test_list_books(self):
            response = self.client.get(self.list_url)
            self.assertEqual(response.status_code, 200)
            self.assertEqual(len(response.data['results']), 1)
    
        def test_create_book(self):
            data = {
                'title': 'Advanced DRF',
                'author': 'Jane Smith',
                'published_date': '2024-05-10',
                'isbn': '9876543210987',
                'price': '39.99'
            }
            response = self.client.post(self.list_url, data, format='json')
            self.assertEqual(response.status_code, 201)
            self.assertEqual(Book.objects.count(), 2)
    

    Deploying DRF Applications

    When you’re ready to go live, follow these production‑ready steps:

    1. Use a dedicated WSGI server such as gunicorn or uvicorn (for ASGI).
    2. Serve static files with whitenoise or a CDN.
    3. Secure the API with HTTPS (Let’s Encrypt) and proper CORS settings (django-cors-headers).
    4. Database optimization – enable connection pooling (e.g., pgbouncer for PostgreSQL).
    5. Environment variables