<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Huy Nguyen</title>
    <description>The latest articles on DEV Community by Huy Nguyen (@huynguyengl99).</description>
    <link>https://dev.to/huynguyengl99</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1654565%2F9f1c9a82-ef1d-447c-9b5c-f8ebaf086c6e.jpeg</url>
      <title>DEV Community: Huy Nguyen</title>
      <link>https://dev.to/huynguyengl99</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/huynguyengl99"/>
    <language>en</language>
    <item>
      <title>🚀 Supercharge Your FastAPI WebSockets with Channel Layers &amp; Group Messaging</title>
      <dc:creator>Huy Nguyen</dc:creator>
      <pubDate>Thu, 18 Sep 2025 02:38:11 +0000</pubDate>
      <link>https://dev.to/huynguyengl99/supercharge-your-fastapi-websockets-with-channel-layers-group-messaging-19kb</link>
      <guid>https://dev.to/huynguyengl99/supercharge-your-fastapi-websockets-with-channel-layers-group-messaging-19kb</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvl9ejtloufsvls5rnuf2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvl9ejtloufsvls5rnuf2.png" alt=" " width="800" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Building real-time features in FastAPI? Hit the wall trying to send messages from HTTP endpoints to WebSocket clients? Struggling with group messaging and scalability?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fast Channels&lt;/strong&gt; brings Django Channels' battle-tested architecture to FastAPI and the entire ASGI ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pain Points We've All Hit
&lt;/h2&gt;

&lt;p&gt;FastAPI's native WebSocket support gets you started, but quickly becomes limiting:&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;No group messaging&lt;/strong&gt; - can't broadcast to multiple connections&lt;br&gt;&lt;br&gt;
❌ &lt;strong&gt;No cross-process communication&lt;/strong&gt; - HTTP endpoints can't reach WebSocket clients&lt;br&gt;&lt;br&gt;
❌ &lt;strong&gt;Manual connection management&lt;/strong&gt; - tracking users, rooms, cleanup&lt;br&gt;&lt;br&gt;
❌ &lt;strong&gt;No scalability&lt;/strong&gt; - everything breaks with multiple server instances&lt;br&gt;&lt;br&gt;
❌ &lt;strong&gt;Testing nightmare&lt;/strong&gt; - WebSocket unit tests are painful to write  &lt;/p&gt;
&lt;h2&gt;
  
  
  What Fast Channels Delivers
&lt;/h2&gt;

&lt;p&gt;✅ &lt;strong&gt;Group messaging&lt;/strong&gt; - broadcast to chat rooms, user segments, notification groups&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Cross-process communication&lt;/strong&gt; - HTTP → WebSocket, background workers → clients&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Auto connection management&lt;/strong&gt; - join/leave groups automatically&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Multi-instance scaling&lt;/strong&gt; - Redis-backed message routing&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Built-in testing framework&lt;/strong&gt; - proper WebSocket test utilities&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Consumer patterns&lt;/strong&gt; - WebSocket handlers that feel like FastAPI views  &lt;/p&gt;
&lt;h2&gt;
  
  
  Battle-Tested in Production
&lt;/h2&gt;

&lt;p&gt;This isn't experimental tech. Django Channels has powered real-time features for &lt;strong&gt;millions of users&lt;/strong&gt; across thousands of production applications for years. Fast Channels brings that same proven architecture to FastAPI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Simple but powerful
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatConsumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AsyncWebsocketConsumer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;groups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_room&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Auto-join on connect
&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Broadcast to all users in the room
&lt;/span&gt;        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;channel_layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_room&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text_data&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Production-Ready Features
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Redis Integration&lt;/strong&gt;: Full Redis support with Sentinel for high availability&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Multiple Backends&lt;/strong&gt;: In-memory for testing, Redis Queue for reliability, Redis Pub/Sub for speed&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Type Safety&lt;/strong&gt;: Complete mypy and pyright support&lt;br&gt;&lt;br&gt;
&lt;strong&gt;ASGI Universal&lt;/strong&gt;: Works with FastAPI, Starlette, Quart, any ASGI framework&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Testing Built-in&lt;/strong&gt;: Comprehensive WebSocket testing utilities  &lt;/p&gt;

&lt;h2&gt;
  
  
  FastAPI vs Fast Channels vs Alternatives
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Native FastAPI&lt;/th&gt;
&lt;th&gt;Broadcaster&lt;/th&gt;
&lt;th&gt;Fast Channels&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Basic WebSocket&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Group messaging&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Consumer patterns&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Message persistence&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testing framework&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto connection mgmt&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-process msgs&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production battle-tested&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Real-World Impact
&lt;/h2&gt;

&lt;p&gt;Teams are using Fast Channels for:&lt;/p&gt;

&lt;p&gt;🏪 &lt;strong&gt;E-commerce&lt;/strong&gt;: Live inventory, order tracking, flash sale updates&lt;br&gt;&lt;br&gt;
💬 &lt;strong&gt;Chat platforms&lt;/strong&gt;: Real-time messaging, typing indicators, presence&lt;br&gt;&lt;br&gt;
📊 &lt;strong&gt;Dashboards&lt;/strong&gt;: Live metrics, system monitoring, alerts&lt;br&gt;&lt;br&gt;
🎮 &lt;strong&gt;Gaming&lt;/strong&gt;: Multiplayer sync, leaderboards, real-time events&lt;br&gt;&lt;br&gt;
🔔 &lt;strong&gt;Notifications&lt;/strong&gt;: Push alerts, system updates, user notifications  &lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;fast-channels[redis]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Register a channel layer, create a consumer, add to FastAPI - done. Your WebSockets now scale across multiple processes and servers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why It Matters
&lt;/h2&gt;

&lt;p&gt;Real-time features shouldn't require reinventing messaging infrastructure. Fast Channels gives you Django's proven patterns with FastAPI's developer experience - the best of both worlds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production-ready&lt;/strong&gt;: Redis Sentinel support, proper error handling, connection cleanup&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Developer-friendly&lt;/strong&gt;: Type safety, testing utilities, clear documentation&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Scalable&lt;/strong&gt;: Multi-process, multi-server, battle-tested architecture  &lt;/p&gt;

&lt;p&gt;Stop building WebSocket boilerplate. Start building features.&lt;/p&gt;




&lt;p&gt;🔗 &lt;strong&gt;Links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/huynguyengl99/fast-channels" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pypi.org/project/fast-channels/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fast-channels.readthedocs.io/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fast-channels.readthedocs.io/en/latest/tutorial/index.html" rel="noopener noreferrer"&gt;Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Building real-time features? What's your biggest WebSocket challenge? 👇&lt;/em&gt;&lt;/p&gt;

</description>
      <category>fastapi</category>
      <category>websocket</category>
    </item>
    <item>
      <title>Building a Modern, Type-Safe Authentication System for Django REST Framework</title>
      <dc:creator>Huy Nguyen</dc:creator>
      <pubDate>Wed, 09 Jul 2025 13:59:32 +0000</pubDate>
      <link>https://dev.to/huynguyengl99/building-a-modern-type-safe-authentication-system-for-django-rest-framework-c42</link>
      <guid>https://dev.to/huynguyengl99/building-a-modern-type-safe-authentication-system-for-django-rest-framework-c42</guid>
      <description>&lt;p&gt;Have you ever spent hours fighting with authentication setup in your Django REST API? Or struggled with type errors that could have been caught at development time? Or wished your API documentation would just... work automatically?&lt;/p&gt;

&lt;p&gt;I've been there. After years of wrestling with existing Django authentication packages, I decided to build something better: &lt;strong&gt;DRF Auth Kit&lt;/strong&gt; – a modern, type-safe authentication toolkit that just works.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Authentication Shouldn't Be This Hard
&lt;/h2&gt;

&lt;p&gt;Let me paint a picture. You're building a modern web app with a Django REST API backend. You need:&lt;/p&gt;

&lt;p&gt;✅ JWT authentication with cookie support&lt;/p&gt;

&lt;p&gt;✅ Multi-factor authentication&lt;/p&gt;

&lt;p&gt;✅ Social login (Google, GitHub, etc.)&lt;/p&gt;

&lt;p&gt;✅ Automatic API documentation&lt;/p&gt;

&lt;p&gt;✅ Type safety throughout&lt;/p&gt;

&lt;p&gt;With existing solutions, you'd typically:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install 3-4 different packages&lt;/li&gt;
&lt;li&gt;Write custom serializers and views&lt;/li&gt;
&lt;li&gt;Manually configure complex URL patterns&lt;/li&gt;
&lt;li&gt;Struggle with type hints and documentation&lt;/li&gt;
&lt;li&gt;Debug cryptic authentication errors&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;There had to be a better way.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: DRF Auth Kit
&lt;/h2&gt;

&lt;p&gt;DRF Auth Kit is what I wish existed when I started building Django APIs. Here's what makes it different:&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 One Package, Everything Included
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Get everything you need&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;drf-auth-kit[all]

&lt;span class="c"&gt;# Or pick what you need&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;drf-auth-kit[mfa]     &lt;span class="c"&gt;# + Multi-factor auth&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;drf-auth-kit[social]  &lt;span class="c"&gt;# + Social authentication&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔒 Universal Authentication Backend
&lt;/h3&gt;

&lt;p&gt;Instead of juggling multiple authentication classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# settings.py
&lt;/span&gt;&lt;span class="n"&gt;REST_FRAMEWORK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;DEFAULT_AUTHENTICATION_CLASSES&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auth_kit.authentication.AuthKitAuthentication&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;AUTH_KIT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AUTH_TYPE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;jwt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# or 'token', 'custom'
&lt;/span&gt;    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;USE_AUTH_COOKIE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;USE_MFA&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This single configuration handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JWT tokens with automatic refresh&lt;/li&gt;
&lt;li&gt;DRF token authentication&lt;/li&gt;
&lt;li&gt;Custom authentication backends&lt;/li&gt;
&lt;li&gt;HTTP-only cookies with security headers&lt;/li&gt;
&lt;li&gt;Multi-factor authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🛠️ Intelligent URL Management
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Conditional URL patterns&lt;/strong&gt; - URLs automatically included/excluded based on settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# When USE_MFA=True, automatically creates:
# POST /api/auth/login/         # First step (password)
# POST /api/auth/login/verify/  # Second step (MFA code)
# POST /api/auth/login/change-method/
# POST /api/auth/login/resend/
# GET /api/auth/mfa/           # MFA management endpoints
&lt;/span&gt;
&lt;span class="c1"&gt;# When USE_MFA=False, creates:
# POST /api/auth/login/         # Direct login
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Social authentication&lt;/strong&gt; - automatic endpoint generation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Just add a provider to INSTALLED_APPS:
&lt;/span&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;allauth.socialaccount.providers.google&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auth_kit.social&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Automatically creates:
# POST /api/auth/social/google/
# POST /api/auth/social/google/connect/
# GET /api/auth/social/accounts/
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📝 Type Safety That Actually Works
&lt;/h3&gt;

&lt;p&gt;Every component includes comprehensive type hints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;auth_kit.authentication&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AuthKitAuthentication&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;auth_kit.serializers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LoginRequestSerializer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;auth_kit.views&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LoginView&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Full mypy and pyright compatibility&lt;/strong&gt; with comprehensive type hints throughout the codebase. Your IDE will thank you. No more guessing what parameters a function expects or what a setting does.&lt;/p&gt;

&lt;h3&gt;
  
  
  📚 API Documentation That Updates Itself
&lt;/h3&gt;

&lt;p&gt;Integration with DRF Spectacular means your API docs are always current:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Zero configuration needed
&lt;/span&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;drf_spectacular&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auth_kit&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit &lt;code&gt;/api/docs/&lt;/code&gt; and you'll see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interactive Swagger UI&lt;/li&gt;
&lt;li&gt;Complete request/response schemas&lt;/li&gt;
&lt;li&gt;Authentication flow examples&lt;/li&gt;
&lt;li&gt;Working test interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpf0r3jm4h4v1fjvckcho.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpf0r3jm4h4v1fjvckcho.png" alt="API Documentation Example" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🛡️ MFA Made Simple
&lt;/h3&gt;

&lt;p&gt;Multi-factor authentication that doesn't require a PhD:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Enable MFA
&lt;/span&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auth_kit&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auth_kit.mfa&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Just add this!
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;AUTH_KIT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;USE_MFA&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# URLs automatically reconfigure
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Automatic URL reconfiguration&lt;/strong&gt; when MFA is enabled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Login endpoint becomes two-step flow&lt;/li&gt;
&lt;li&gt;MFA management endpoints automatically created&lt;/li&gt;
&lt;li&gt;All endpoints documented in your OpenAPI schema&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Email-based MFA with HTML/text templates&lt;/li&gt;
&lt;li&gt;Authenticator app support (Google Authenticator, Authy)&lt;/li&gt;
&lt;li&gt;Backup codes for account recovery&lt;/li&gt;
&lt;li&gt;Extensible system for custom MFA methods&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The login flow becomes a clean two-step process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Username/password → Get ephemeral token&lt;/li&gt;
&lt;li&gt;MFA code → Get final auth tokens&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  🌐 Social Authentication That Just Works
&lt;/h3&gt;

&lt;p&gt;Social login with 50+ providers and &lt;strong&gt;automatic URL generation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auth_kit&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auth_kit.social&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Automatic URL generation
&lt;/span&gt;    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;allauth.socialaccount.providers.google&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;allauth.socialaccount.providers.github&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;# Add any provider, URLs created automatically!
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# URLs are automatically created for each provider:
# POST /api/auth/social/google/
# POST /api/auth/social/github/
# POST /api/auth/social/google/connect/
# POST /api/auth/social/github/connect/
# GET /api/auth/social/accounts/
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;No manual URL configuration needed!&lt;/strong&gt; The system scans your installed providers and creates endpoints automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  🍪 Security-First Cookie Authentication
&lt;/h3&gt;

&lt;p&gt;HTTP-only cookies with all the security features:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;AUTH_KIT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;USE_AUTH_COOKIE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AUTH_COOKIE_SECURE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;# HTTPS only
&lt;/span&gt;    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AUTH_COOKIE_HTTPONLY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;# No JavaScript access
&lt;/span&gt;    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AUTH_COOKIE_SAMESITE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Lax&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# CSRF protection
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perfect for modern web apps where you want security without complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Example: Complete Auth Setup
&lt;/h2&gt;

&lt;p&gt;Here's how you'd set up a complete authentication system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# settings.py
&lt;/span&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rest_framework&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auth_kit&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auth_kit.mfa&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auth_kit.social&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;allauth&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;allauth.account&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;allauth.socialaccount&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;allauth.socialaccount.providers.google&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;REST_FRAMEWORK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;DEFAULT_AUTHENTICATION_CLASSES&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auth_kit.authentication.AuthKitAuthentication&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;AUTH_KIT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AUTH_TYPE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;jwt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;USE_AUTH_COOKIE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;USE_MFA&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Social auth providers
&lt;/span&gt;&lt;span class="n"&gt;SOCIALACCOUNT_PROVIDERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;google&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SCOPE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;profile&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AUTH_PARAMS&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;access_type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;online&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;OAUTH_PKCE_ENABLED&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;APP&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;client_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;your-google-client-id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;secret&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;your-google-client-secret&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# urls.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.urls&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;api/auth/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auth_kit.urls&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;api/auth/social/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auth_kit.social.urls&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! You now have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JWT authentication with cookies&lt;/li&gt;
&lt;li&gt;User registration and email verification&lt;/li&gt;
&lt;li&gt;Password reset functionality&lt;/li&gt;
&lt;li&gt;Multi-factor authentication&lt;/li&gt;
&lt;li&gt;Social login with Google&lt;/li&gt;
&lt;li&gt;Complete API documentation&lt;/li&gt;
&lt;li&gt;Type safety throughout&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Customization: Make It Yours
&lt;/h2&gt;

&lt;p&gt;Need custom behavior? Override any component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Custom login serializer
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomLoginSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LoginRequestSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;remember_me&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BooleanField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;attrs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Your custom logic here
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;

&lt;span class="c1"&gt;# Apply it
&lt;/span&gt;&lt;span class="n"&gt;AUTH_KIT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LOGIN_REQUEST_SERIALIZER&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;myapp.serializers.CustomLoginSerializer&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Want a custom MFA method? Easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SMSMFAHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseMFAHandler&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Your SMS implementation
&lt;/span&gt;        &lt;span class="nf"&gt;send_sms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Your verification code: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Register it
&lt;/span&gt;&lt;span class="n"&gt;AUTH_KIT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;MFA_HANDLERS&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auth_kit.mfa.handlers.app.MFAAppHandler&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auth_kit.mfa.handlers.email.MFAEmailHandler&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;myapp.handlers.SMSMFAHandler&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Production-Ready Features
&lt;/h2&gt;

&lt;p&gt;DRF Auth Kit isn't just for prototypes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Comprehensive test coverage&lt;/strong&gt; (&amp;gt;95%) across multiple Python/Django versions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internationalization&lt;/strong&gt; support for 57 languages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security best practices&lt;/strong&gt; built-in&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance optimized&lt;/strong&gt; with efficient database queries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limiting&lt;/strong&gt; and &lt;strong&gt;audit logging&lt;/strong&gt; (coming soon)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Numbers Don't Lie
&lt;/h2&gt;

&lt;p&gt;Here's how DRF Auth Kit compares to existing solutions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;dj-rest-auth&lt;/th&gt;
&lt;th&gt;django-trench&lt;/th&gt;
&lt;th&gt;DRF Auth Kit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Type Safety&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ Full mypy/pyright&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto OpenAPI&lt;/td&gt;
&lt;td&gt;⚠️ Partial&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ Complete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cookie Auth&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ Enhanced&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MFA Support&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ Simplified&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Social Auth&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ Better integration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom Auth&lt;/td&gt;
&lt;td&gt;⚠️ Complex&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ Easy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I18n Support&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ 57 languages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test Coverage&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;✅ &amp;gt;95%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Try It Today
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;drf-auth-kit[all]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out the &lt;a href="https://drf-auth-kit.readthedocs.io/" rel="noopener noreferrer"&gt;complete documentation&lt;/a&gt; for detailed guides, examples, and API reference.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;The roadmap includes exciting features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WebAuthn support&lt;/strong&gt; for passwordless authentication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardware security keys&lt;/strong&gt; (YubiKey, FIDO2)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limiting&lt;/strong&gt; and &lt;strong&gt;audit logging&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advanced security features&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Join the Community
&lt;/h2&gt;

&lt;p&gt;DRF Auth Kit is open source and built by developers, for developers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/forthecraft/drf-auth-kit" rel="noopener noreferrer"&gt;github.com/forthecraft/drf-auth-kit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt;: &lt;a href="https://drf-auth-kit.readthedocs.io/" rel="noopener noreferrer"&gt;drf-auth-kit.readthedocs.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PyPI&lt;/strong&gt;: &lt;a href="https://pypi.org/project/drf-auth-kit/" rel="noopener noreferrer"&gt;pypi.org/project/drf-auth-kit&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Building authentication shouldn't be a painful experience. With DRF Auth Kit, you get a modern, type-safe solution that grows with your project – from simple JWT authentication to complex multi-factor flows.&lt;/p&gt;

&lt;p&gt;The combination of type safety, automatic documentation, and developer-friendly APIs makes it perfect for both new projects and existing ones looking to modernize their authentication.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are you waiting for?&lt;/strong&gt; Give it a try in your next project and let me know what you think! 🚀&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>authentication</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Chanx: The Missing Toolkit for Django Channels - Production-Ready WebSockets Made Simple</title>
      <dc:creator>Huy Nguyen</dc:creator>
      <pubDate>Wed, 11 Jun 2025 08:13:18 +0000</pubDate>
      <link>https://dev.to/huynguyengl99/chanx-the-missing-toolkit-for-django-channels-production-ready-websockets-made-simple-27om</link>
      <guid>https://dev.to/huynguyengl99/chanx-the-missing-toolkit-for-django-channels-production-ready-websockets-made-simple-27om</guid>
      <description>&lt;p&gt;&lt;em&gt;Building WebSocket applications with Django Channels just got a whole lot easier&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Django Channels
&lt;/h2&gt;

&lt;p&gt;Don't get me wrong - Django Channels is fantastic for adding WebSocket support to Django applications. But after building several real-time apps, I kept running into the same challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up authentication for WebSocket connections&lt;/li&gt;
&lt;li&gt;Validating message structures and preventing runtime errors&lt;/li&gt;
&lt;li&gt;Testing multi-user WebSocket interactions&lt;/li&gt;
&lt;li&gt;Managing group messaging patterns&lt;/li&gt;
&lt;li&gt;Debugging WebSocket connections during development&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I found myself writing the same boilerplate code over and over. So I built &lt;strong&gt;Chanx&lt;/strong&gt; to solve these problems once and for all.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Chanx?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/huynguyengl99/chanx" rel="noopener noreferrer"&gt;Chanx&lt;/a&gt; is a comprehensive toolkit that extends Django Channels with production-ready features. Think of it as what Django REST Framework is to Django views - but for WebSocket consumers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features That'll Save You Hours
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔐 DRF-Style Authentication
&lt;/h3&gt;

&lt;p&gt;Use your existing authentication classes with WebSockets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;chanx.generic.websocket&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AsyncJsonWebsocketConsumer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rest_framework.authentication&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SessionAuthentication&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rest_framework.permissions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;IsAuthenticated&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatConsumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AsyncJsonWebsocketConsumer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="n"&gt;authentication_classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SessionAuthentication&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;permission_classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;IsAuthenticated&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;receive_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Only authenticated users reach here
&lt;/span&gt;        &lt;span class="c1"&gt;# self.user is automatically populated
&lt;/span&gt;        &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📝 Type-Safe Messaging with Pydantic
&lt;/h3&gt;

&lt;p&gt;No more runtime errors from malformed messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;chanx.messages.base&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseMessage&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseMessage&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotificationMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseMessage&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;notify&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;notify&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;

&lt;span class="c1"&gt;# Union type for type safety
&lt;/span&gt;&lt;span class="n"&gt;AllMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ChatMessage&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;NotificationMessage&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyConsumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AsyncJsonWebsocketConsumer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;AllMessages&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;receive_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AllMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Pattern matching with full type safety
&lt;/span&gt;        &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handle_chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;NotificationMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handle_notification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🎮 WebSocket Playground
&lt;/h3&gt;

&lt;p&gt;Like Swagger, but for WebSockets! Auto-discovers your endpoints and lets you test them interactively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# settings.py
&lt;/span&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;chanx.playground&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# urls.py
&lt;/span&gt;&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;playground/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;chanx.playground.urls&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit &lt;code&gt;/playground/websocket/&lt;/code&gt; and test your WebSocket endpoints without writing JavaScript!&lt;/p&gt;

&lt;h3&gt;
  
  
  👥 Simplified Group Messaging
&lt;/h3&gt;

&lt;p&gt;Pub/sub messaging made easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatConsumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AsyncJsonWebsocketConsumer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_groups&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;room_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url_route&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kwargs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;room_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_room_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;room_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;receive_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Broadcast to all users in the room
&lt;/span&gt;        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_group_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Messages automatically include metadata:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"chat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"payload"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello everyone!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_mine"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_current"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🧪 Testing That Actually Works
&lt;/h3&gt;

&lt;p&gt;Multi-user WebSocket testing without the headaches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;chanx.testing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;WebsocketTestCase&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WebsocketTestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ws_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/ws/chat/room1/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_multi_user_chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# First user (automatic setup)
&lt;/span&gt;        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth_communicator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth_communicator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assert_authenticated_status_ok&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;# Second user with different credentials
&lt;/span&gt;        &lt;span class="n"&gt;user2_comm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_communicator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user2_headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;user2_comm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;# Test group messaging
&lt;/span&gt;        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth_communicator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;responses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;user2_comm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive_all_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wait_group&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payload&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_mine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real-World Example: Building a Chat App
&lt;/h2&gt;

&lt;p&gt;Here's how simple it is to build a production-ready chat application:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Define Your Messages
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;chanx.messages.base&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BaseGroupMessage&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseMessage&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserJoinedMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseGroupMessage&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_joined&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_joined&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;

&lt;span class="n"&gt;ChatMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ChatMessage&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;PingMessage&lt;/span&gt;  &lt;span class="c1"&gt;# Include ping for health checks
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Create Your Consumer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;chanx.generic.websocket&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AsyncJsonWebsocketConsumer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;chanx.messages.incoming&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PingMessage&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;chanx.messages.outgoing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PongMessage&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatConsumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AsyncJsonWebsocketConsumer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ChatMessages&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="n"&gt;authentication_classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SessionAuthentication&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;permission_classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;IsAuthenticated&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_groups&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;room_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url_route&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kwargs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;room_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_room_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;room_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;post_authentication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Called after successful authentication&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_group_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;UserJoinedMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;receive_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ChatMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;PingMessage&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PongMessage&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="n"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="c1"&gt;# Save to database and broadcast
&lt;/span&gt;                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_group_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Set Up Routing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# chat/routing.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;chanx.routing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;channels.routing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;URLRouter&lt;/span&gt;

&lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;URLRouter&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;int:room_id&amp;gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChatConsumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_asgi&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# project/routing.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;chanx.routing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;channels.routing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;URLRouter&lt;/span&gt;

&lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;URLRouter&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ws/chat/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat.routing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Test It
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatRoomTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WebsocketTestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ws_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/ws/chat/123/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_user_can_join_and_chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth_communicator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth_communicator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assert_authenticated_status_ok&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;# Should receive user_joined message
&lt;/span&gt;        &lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth_communicator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive_all_json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;action&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_joined&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Send a chat message
&lt;/span&gt;        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth_communicator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;responses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth_communicator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive_all_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wait_group&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;action&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payload&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Developers Love Chanx
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Complete Type Safety
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Generic type parameters for compile-time checking
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyConsumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AsyncJsonWebsocketConsumer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;IncomingMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Required: Your message types
&lt;/span&gt;    &lt;span class="n"&gt;ChannelEvents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;# Optional: Channel layer events
&lt;/span&gt;    &lt;span class="n"&gt;Room&lt;/span&gt;              &lt;span class="c1"&gt;# Optional: Model for object permissions
&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="n"&gt;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# For object-level permissions
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enhanced Routing
&lt;/h3&gt;

&lt;p&gt;Django-style routing specifically designed for WebSockets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;chanx.routing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;

&lt;span class="c1"&gt;# Use familiar Django patterns
&lt;/span&gt;&lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;URLRouter&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;room/&amp;lt;str:room_name&amp;gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChatConsumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_asgi&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="nf"&gt;re_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^admin/(?P&amp;lt;id&amp;gt;\d+)/$&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AdminConsumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_asgi&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api.routing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Channel Events
&lt;/h3&gt;

&lt;p&gt;Type-safe communication between consumers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Send events from views, tasks, or other consumers
&lt;/span&gt;&lt;span class="n"&gt;ChatConsumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_channel_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_room_123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;NotificationEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;System update&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Handle in consumer
&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;receive_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;NotificationEvent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;NotificationEvent&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SystemMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;chanx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Essential links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📚 &lt;a href="https://chanx.readthedocs.io/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt; - Comprehensive guides and examples&lt;/li&gt;
&lt;li&gt;💻 &lt;a href="https://github.com/huynguyengl99/chanx" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; - Source code and issues&lt;/li&gt;
&lt;li&gt;🚀 &lt;a href="https://github.com/huynguyengl99/chanx-example" rel="noopener noreferrer"&gt;Complete Example&lt;/a&gt; - Production-ready chat app&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Quick setup:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# settings.py
&lt;/span&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;channels&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rest_framework&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;chanx.playground&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# For WebSocket testing UI
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;CHANX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SEND_COMPLETION&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Important for testing
&lt;/span&gt;    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SEND_AUTHENTICATION_MESSAGE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Perfect for AI Applications
&lt;/h2&gt;

&lt;p&gt;Chanx is especially powerful for AI chatbots and streaming applications:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_ai_chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Stream AI response token by token&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_ai_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AIStreamingMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Community and Feedback
&lt;/h2&gt;

&lt;p&gt;Chanx is actively maintained and used in production applications. The community is growing, and I'm always looking for feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What challenges are you facing with Django Channels?&lt;/li&gt;
&lt;li&gt;Which features would be most valuable to you?&lt;/li&gt;
&lt;li&gt;How can we make WebSocket development even easier?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Django Channels is powerful, but building production WebSocket applications shouldn't require reinventing the wheel every time. Chanx provides the missing pieces:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Authentication&lt;/strong&gt; - DRF integration out of the box&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Type Safety&lt;/strong&gt; - Catch errors at development time&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Testing&lt;/strong&gt; - Multi-user scenarios made simple&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Developer Tools&lt;/strong&gt; - WebSocket playground for debugging&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Group Messaging&lt;/strong&gt; - Pub/sub patterns simplified&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Production Ready&lt;/strong&gt; - Battle-tested in real applications  &lt;/p&gt;

&lt;p&gt;Whether you're building a chat application, real-time collaboration tool, or AI-powered interface, Chanx helps you ship faster with fewer bugs.&lt;/p&gt;

&lt;p&gt;Try it out and let me know what you think! 🚀&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What's your experience with Django Channels? Have you run into similar challenges? Share your thoughts in the comments!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>django</category>
      <category>websockets</category>
      <category>python</category>
      <category>chatbot</category>
    </item>
    <item>
      <title>🚀 Streamline Your Python &amp; Django Development with Production-Ready Cookiecutter Templates</title>
      <dc:creator>Huy Nguyen</dc:creator>
      <pubDate>Mon, 09 Jun 2025 15:18:53 +0000</pubDate>
      <link>https://dev.to/huynguyengl99/streamline-your-python-django-development-with-production-ready-cookiecutter-templates-455o</link>
      <guid>https://dev.to/huynguyengl99/streamline-your-python-django-development-with-production-ready-cookiecutter-templates-455o</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: I've created a comprehensive cookiecutter template collection that generates production-ready Python apps, PyPI packages, Django REST APIs, and DRF packages with modern tooling, best practices, and zero configuration hassle.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: Starting Projects Shouldn't Be This Hard
&lt;/h2&gt;

&lt;p&gt;How many times have you started a new Python project and spent hours setting up the same boilerplate code? Configuring &lt;code&gt;pyproject.toml&lt;/code&gt;, setting up pre-commit hooks, writing GitHub Actions, configuring Docker, setting up Django with all the modern best practices... &lt;/p&gt;

&lt;p&gt;The list goes on. And then you realize you forgot to configure type checking, or your test coverage setup is broken, or you're missing that one crucial piece of tooling that makes development smooth.&lt;/p&gt;

&lt;p&gt;I've been there. We've all been there.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: One Template to Rule Them All (Actually, Four)
&lt;/h2&gt;

&lt;p&gt;That's why I created &lt;strong&gt;&lt;a href="https://github.com/huynguyengl99/cookiecutter-python" rel="noopener noreferrer"&gt;cookiecutter-python&lt;/a&gt;&lt;/strong&gt; — a curated collection of four specialized cookiecutter templates that cover the most common Python development scenarios:&lt;/p&gt;

&lt;h3&gt;
  
  
  🐍 &lt;strong&gt;Python App&lt;/strong&gt; - For General-Purpose Applications
&lt;/h3&gt;

&lt;p&gt;Perfect for CLI tools, data processing scripts, or any standalone Python application.&lt;/p&gt;

&lt;h3&gt;
  
  
  📦 &lt;strong&gt;Python Package&lt;/strong&gt; - For PyPI Publishing
&lt;/h3&gt;

&lt;p&gt;Ready-to-publish package structure with documentation, CI/CD, and multiple license options.&lt;/p&gt;

&lt;h3&gt;
  
  
  🌐 &lt;strong&gt;Django REST App&lt;/strong&gt; - For Full-Stack Web APIs
&lt;/h3&gt;

&lt;p&gt;Complete Django REST Framework setup with authentication, database, optional Celery/WebSockets, and cloud deployment support.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧩 &lt;strong&gt;DRF Package&lt;/strong&gt; - For Reusable Django Components
&lt;/h3&gt;

&lt;p&gt;Lightweight structure for building and distributing Django REST Framework extensions.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Makes These Templates Special?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✨ &lt;strong&gt;Modern Tooling Out of the Box&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Each template is carefully configured with specialized tooling for its use case:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔧 Universal Tools (All Templates):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/astral-sh/uv" rel="noopener noreferrer"&gt;UV&lt;/a&gt;&lt;/strong&gt; for lightning-fast dependency management with intelligent dependency groups&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/astral-sh/ruff" rel="noopener noreferrer"&gt;Ruff&lt;/a&gt;&lt;/strong&gt; for blazing-fast linting and formatting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/psf/black" rel="noopener noreferrer"&gt;Black&lt;/a&gt;&lt;/strong&gt; for consistent code formatting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dual type checking&lt;/strong&gt; with both &lt;strong&gt;&lt;a href="https://mypy.readthedocs.io/" rel="noopener noreferrer"&gt;mypy&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://github.com/microsoft/pyright" rel="noopener noreferrer"&gt;pyright&lt;/a&gt;&lt;/strong&gt; for maximum type safety&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pre-commit hooks&lt;/strong&gt; for automated quality checks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pytest&lt;/strong&gt; with parallel execution (&lt;code&gt;pytest-xdist&lt;/code&gt;) and coverage reporting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Actions&lt;/strong&gt; CI/CD pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;📦 Package Templates (PyPackage &amp;amp; DRF Package) Add:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://commitizen-tools.github.io/commitizen/" rel="noopener noreferrer"&gt;Commitizen&lt;/a&gt;&lt;/strong&gt; for conventional commits and automated versioning&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://interrogate.readthedocs.io/" rel="noopener noreferrer"&gt;Interrogate&lt;/a&gt;&lt;/strong&gt; for docstring coverage monitoring with badge generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.sphinx-doc.org/" rel="noopener noreferrer"&gt;Sphinx&lt;/a&gt;&lt;/strong&gt; ecosystem for professional documentation (myst-parser, ReadTheDocs theme)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated publishing&lt;/strong&gt; workflows to PyPI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🌐 Django Templates (DRF &amp;amp; DRF Package) Add:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://factoryboy.readthedocs.io/" rel="noopener noreferrer"&gt;Factory Boy&lt;/a&gt;&lt;/strong&gt; for realistic test data generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://faker.readthedocs.io/" rel="noopener noreferrer"&gt;Faker&lt;/a&gt;&lt;/strong&gt; for generating fake data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/typeddjango/django-stubs" rel="noopener noreferrer"&gt;django-stubs&lt;/a&gt;&lt;/strong&gt; + &lt;strong&gt;&lt;a href="https://github.com/typeddjango/djangorestframework-stubs" rel="noopener noreferrer"&gt;djangorestframework-stubs&lt;/a&gt;&lt;/strong&gt; for comprehensive Django type checking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://django-debug-toolbar.readthedocs.io/" rel="noopener noreferrer"&gt;django-debug-toolbar&lt;/a&gt;&lt;/strong&gt; for development debugging&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://ipython.org/" rel="noopener noreferrer"&gt;IPython&lt;/a&gt;&lt;/strong&gt; for enhanced Django shell experience&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/spulec/freezegun" rel="noopener noreferrer"&gt;Freezegun&lt;/a&gt;&lt;/strong&gt; for time-based testing&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🏗️ &lt;strong&gt;Production-Ready Architecture&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Django templates include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL&lt;/strong&gt; integration with connection pooling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis&lt;/strong&gt; support for Celery and WebSockets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JWT authentication&lt;/strong&gt; with django-rest-auth&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API documentation&lt;/strong&gt; with Swagger/ReDoc&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker&lt;/strong&gt; containerization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud storage&lt;/strong&gt; support (AWS S3, GCP, Azure)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email providers&lt;/strong&gt; integration (SendGrid, Mailgun, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🎯 &lt;strong&gt;Zero Configuration Philosophy&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Each generated project is immediately runnable. No additional setup required. Just generate, install dependencies, and start developing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Start Guide
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;First, you'll need to install cookiecutter. I recommend using Homebrew (macOS) or pipx for a clean installation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;macOS (Recommended):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;cookiecutter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Linux/Windows with pipx:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pipx &lt;span class="nb"&gt;install &lt;/span&gt;cookiecutter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Alternative (with pip):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--user&lt;/span&gt; cookiecutter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why not just &lt;code&gt;pip install cookiecutter&lt;/code&gt;?&lt;/strong&gt; Since we'll be using UV for Python dependency management in the generated projects, keeping cookiecutter isolated prevents potential conflicts and keeps your global Python environment clean.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Generate Your Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cookiecutter gh:huynguyengl99/cookiecutter-python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll be prompted to select your template type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Select a template
1 - Python app (A cookiecutter template for a normal python app)
2 - Python package (A cookiecutter template for a python package)  
3 - DRF (A cookiecutter template for a django rest framework app)
4 - DRF package (A cookiecutter template for a drf package)
Choose from [1/2/3/4] (1):
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Start Developing Immediately
&lt;/h3&gt;

&lt;p&gt;For a &lt;strong&gt;Django REST App&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;your-project
uv &lt;span class="nb"&gt;sync&lt;/span&gt;                    &lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;       &lt;span class="c"&gt;# Start PostgreSQL/Redis&lt;/span&gt;
scripts/manage.sh migrate  &lt;span class="c"&gt;# Run migrations&lt;/span&gt;
scripts/manage.sh runserver &lt;span class="c"&gt;# Start development server&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your API documentation is immediately available at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Swagger UI: &lt;code&gt;http://localhost:8000/api/schema/swg/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ReDoc: &lt;code&gt;http://localhost:8000/api/schema/redoc/&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Deep Dive: What Each Template Provides
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🐍 Python App Template
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Perfect for&lt;/strong&gt;: CLI tools, data processing, automation scripts&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Includes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modern &lt;code&gt;pyproject.toml&lt;/code&gt; configuration&lt;/li&gt;
&lt;li&gt;Docker setup for easy deployment&lt;/li&gt;
&lt;li&gt;Comprehensive testing framework&lt;/li&gt;
&lt;li&gt;Code quality tools (Ruff, Black, mypy, pyright)&lt;/li&gt;
&lt;li&gt;GitHub Actions for CI/CD&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Generated Structure&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-app/
├── pyproject.toml
├── docker-compose.yml
├── Dockerfile
├── scripts/
│   └── lint.sh
└── my_app/
    └── __init__.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📦 Python Package Template
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Perfect for&lt;/strong&gt;: Open-source libraries, reusable components&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Includes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PyPI-ready project structure&lt;/li&gt;
&lt;li&gt;Sphinx documentation with ReadTheDocs integration&lt;/li&gt;
&lt;li&gt;Multiple license options (MIT, BSD, Apache, GPL)&lt;/li&gt;
&lt;li&gt;Automated versioning with Commitizen&lt;/li&gt;
&lt;li&gt;Publishing workflow to PyPI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Generated Structure&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-package/
├── pyproject.toml
├── LICENSE
├── docs/
├── tests/
├── .github/workflows/
└── my_package/
    └── __init__.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🌐 Django REST App Template
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Perfect for&lt;/strong&gt;: Web APIs, SaaS backends, microservices&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration Options&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Database&lt;/strong&gt;: PostgreSQL with multiple version options&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt;: JWT with optional Google OAuth&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Background Tasks&lt;/strong&gt;: Optional Celery integration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time&lt;/strong&gt;: Optional WebSocket support with Channels&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Storage&lt;/strong&gt;: AWS S3, Google Cloud, Azure support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email&lt;/strong&gt;: 10+ provider integrations (SendGrid, Mailgun, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Style&lt;/strong&gt;: Optional camelCase conversion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Generated Structure&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-api/
├── pyproject.toml
├── docker-compose.yml
├── Dockerfile
├── scripts/
│   └── manage.sh
└── my_api/
    ├── config/
    │   ├── settings/
    │   ├── urls.py
    │   └── wsgi.py
    ├── accounts/        # Custom user model
    ├── core/           # Utilities
    └── status/         # Health check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom User Model&lt;/strong&gt; with email authentication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JWT Authentication&lt;/strong&gt; with refresh token rotation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Versioning&lt;/strong&gt; ready structure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comprehensive Testing&lt;/strong&gt; with factories and fixtures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Admin Interface&lt;/strong&gt; customization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured Logging&lt;/strong&gt; with structured logs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Health Checks&lt;/strong&gt; and monitoring endpoints&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🧩 DRF Package Template
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Perfect for&lt;/strong&gt;: Django REST Framework extensions, reusable API components&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Includes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sandbox Django project for testing&lt;/li&gt;
&lt;li&gt;Documentation with Django integration&lt;/li&gt;
&lt;li&gt;Package publishing to PyPI&lt;/li&gt;
&lt;li&gt;Testing across multiple Django/DRF versions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Unique Feature&lt;/strong&gt;: The sandbox directory serves dual purposes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Testing Environment&lt;/strong&gt;: Run tests against your package&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Development Playground&lt;/strong&gt;: Manual testing with a real Django app&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Advanced Features That Set These Apart
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔧 &lt;strong&gt;Intelligent Dependency Management with UV&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Each template uses UV's dependency groups for optimal development experience:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[dependency-groups]&lt;/span&gt;
&lt;span class="py"&gt;dev&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"commitizen"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"factory-boy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"pytest-django"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c"&gt;# Core development&lt;/span&gt;
&lt;span class="py"&gt;lint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"black"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ruff"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"mypy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"pyright"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;           &lt;span class="c"&gt;# Code quality  &lt;/span&gt;
&lt;span class="py"&gt;test&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"pytest-cov"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"pytest-xdist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"coverage"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    &lt;span class="c"&gt;# Testing tools&lt;/span&gt;
&lt;span class="py"&gt;docs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"sphinx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"myst-parser"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"interrogate"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;      &lt;span class="c"&gt;# Documentation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Smart defaults&lt;/strong&gt; with &lt;code&gt;uv sync&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application templates&lt;/strong&gt;: Auto-installs &lt;code&gt;dev&lt;/code&gt; + &lt;code&gt;lint&lt;/code&gt; groups&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Package templates&lt;/strong&gt;: Auto-installs all groups for comprehensive development&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selective installation&lt;/strong&gt;: &lt;code&gt;uv sync --group test&lt;/code&gt; for specific workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🛡️ &lt;strong&gt;Type Safety First&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Every template includes comprehensive type checking with dual tools for maximum coverage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://mypy.readthedocs.io/" rel="noopener noreferrer"&gt;mypy&lt;/a&gt;&lt;/strong&gt; with specialized Django and DRF plugins for framework-specific type checking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/microsoft/pyright" rel="noopener noreferrer"&gt;pyright&lt;/a&gt;&lt;/strong&gt; for advanced static analysis and fast feedback&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/typeddjango/django-stubs" rel="noopener noreferrer"&gt;django-stubs&lt;/a&gt;&lt;/strong&gt; for comprehensive Django typing (Django templates)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This dual approach catches different categories of type issues and provides the most robust type safety available in the Python ecosystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  📊 &lt;strong&gt;Quality Metrics &amp;amp; Automation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Package templates&lt;/strong&gt; include sophisticated quality monitoring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Docstring coverage with automatic badge generation&lt;/span&gt;
interrogate &lt;span class="nt"&gt;--generate-badge&lt;/span&gt; docs/_static/ my_package

&lt;span class="c"&gt;# Conventional commits with automated versioning&lt;/span&gt;
cz commit  &lt;span class="c"&gt;# Interactive commit creation&lt;/span&gt;
cz bump    &lt;span class="c"&gt;# Automatic version bumping and changelog&lt;/span&gt;

&lt;span class="c"&gt;# Parallel testing for faster feedback&lt;/span&gt;
pytest &lt;span class="nt"&gt;-n5&lt;/span&gt;  &lt;span class="c"&gt;# Runs tests across 5 parallel processes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Quality gates enforce standards:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;80% docstring coverage&lt;/strong&gt; requirement&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;100% type hint coverage&lt;/strong&gt; with mypy strict mode&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero linting violations&lt;/strong&gt; with Ruff and Black&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conventional commit format&lt;/strong&gt; for automated changelog generation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⚡ &lt;strong&gt;Modern Python Practices&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PEP 621&lt;/strong&gt; compliant &lt;code&gt;pyproject.toml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UV&lt;/strong&gt; for dependency management (10x faster than pip)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ruff&lt;/strong&gt; for linting (100x faster than flake8)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.10+&lt;/strong&gt; with modern syntax support&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🚀 &lt;strong&gt;Production Deployment Ready&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Django templates include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-stage Docker builds&lt;/strong&gt; for optimized images&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gunicorn&lt;/strong&gt; configuration for production WSGI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment-based settings&lt;/strong&gt; (dev/test/production)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static file handling&lt;/strong&gt; with WhiteNoise&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database connection pooling&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Real-World Usage Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Scenario 1: Building a SaaS API
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cookiecutter gh:huynguyengl99/cookiecutter-python
&lt;span class="c"&gt;# Select: 3 - DRF&lt;/span&gt;
&lt;span class="c"&gt;# Configure: PostgreSQL, JWT auth, Celery, SendGrid emails, AWS S3&lt;/span&gt;

&lt;span class="nb"&gt;cd &lt;/span&gt;my-saas-api
uv &lt;span class="nb"&gt;sync
&lt;/span&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
scripts/manage.sh migrate
scripts/manage.sh createsuperuser
scripts/manage.sh runserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: Full-featured API with user authentication, background tasks, email integration, and cloud storage. Ready for production deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 2: Publishing a Python Library
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cookiecutter gh:huynguyengl99/cookiecutter-python
&lt;span class="c"&gt;# Select: 2 - Python package&lt;/span&gt;
&lt;span class="c"&gt;# Configure: MIT license, GitHub username, PyPI publishing&lt;/span&gt;

&lt;span class="nb"&gt;cd &lt;/span&gt;my-library
uv &lt;span class="nb"&gt;sync
&lt;/span&gt;pytest  &lt;span class="c"&gt;# Tests pass immediately&lt;/span&gt;
scripts/lint.sh  &lt;span class="c"&gt;# Code quality checks pass&lt;/span&gt;
cz commit  &lt;span class="c"&gt;# Conventional commits&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: Professional package structure ready for PyPI publishing with documentation, CI/CD, and automated releases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 3: Building a DRF Extension
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cookiecutter gh:huynguyengl99/cookiecutter-python
&lt;span class="c"&gt;# Select: 4 - DRF package&lt;/span&gt;

&lt;span class="nb"&gt;cd &lt;/span&gt;my-drf-extension
uv &lt;span class="nb"&gt;sync
&lt;/span&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;  &lt;span class="c"&gt;# Test database&lt;/span&gt;
pytest sandbox  &lt;span class="c"&gt;# Test against real Django app&lt;/span&gt;
python sandbox/manage.py runserver  &lt;span class="c"&gt;# Manual testing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: Professional DRF package with testing sandbox and publishing workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Practices Baked In
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🧪 &lt;strong&gt;Testing Excellence&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Each template includes sophisticated testing infrastructure:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🏃‍♂️ Performance-Optimized Testing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Parallel execution&lt;/strong&gt; with &lt;code&gt;pytest-xdist&lt;/code&gt; (5 parallel processes by default)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart test discovery&lt;/strong&gt; with proper Django integration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coverage reporting&lt;/strong&gt; with branch coverage and XML output for CI integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🏭 Test Data Generation (Django Templates):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Factory Boy integration for realistic test data
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;accounts.factories&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;UserFactory&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_user_creation&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UserFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test@example.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_active&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;⏰ Time-Based Testing:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Freezegun for testing time-dependent code
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;freezegun&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;freeze_time&lt;/span&gt;

&lt;span class="nd"&gt;@freeze_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2023-01-01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_timestamp_behavior&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Test behavior at specific time
&lt;/span&gt;    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;🔧 Advanced Testing Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;pytest-mock&lt;/strong&gt; for sophisticated mocking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pytest-django&lt;/strong&gt; for Django-specific fixtures and database handling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Factory Boy&lt;/strong&gt; with custom factory metaclass for type-safe model factories&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coverage exclusions&lt;/strong&gt; for migrations, settings, and other non-testable code&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📝 &lt;strong&gt;Documentation Standards&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Package templates include professional documentation tooling:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📖 Sphinx Documentation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automatic API documentation&lt;/strong&gt; generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ReadTheDocs&lt;/strong&gt; integration with automated builds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MyST parser&lt;/strong&gt; for Markdown support in reStructuredText projects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-references&lt;/strong&gt; and &lt;strong&gt;intersphinx&lt;/strong&gt; linking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;📊 Documentation Quality Monitoring:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://interrogate.readthedocs.io/" rel="noopener noreferrer"&gt;Interrogate&lt;/a&gt;&lt;/strong&gt; for docstring coverage monitoring&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic badge generation&lt;/strong&gt; showing documentation coverage percentage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;80% coverage requirement&lt;/strong&gt; enforced in CI/CD&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SVG badges&lt;/strong&gt; integrated into documentation and README
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check docstring coverage&lt;/span&gt;
interrogate &lt;span class="nt"&gt;-vv&lt;/span&gt; my_package

&lt;span class="c"&gt;# Generate coverage badge&lt;/span&gt;
interrogate &lt;span class="nt"&gt;--generate-badge&lt;/span&gt; docs/_static/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;📋 API Documentation (Django Templates):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Swagger UI&lt;/strong&gt; and &lt;strong&gt;ReDoc&lt;/strong&gt; auto-generation from code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAPI 3.0&lt;/strong&gt; specification export&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interactive API testing&lt;/strong&gt; directly in documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔄 &lt;strong&gt;CI/CD Pipeline&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;GitHub Actions workflows include:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧪 Comprehensive Testing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-version testing&lt;/strong&gt; across Python 3.10-3.13&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel test execution&lt;/strong&gt; with &lt;code&gt;pytest-xdist&lt;/code&gt; for faster feedback&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coverage reporting&lt;/strong&gt; with Codecov integration and XML output&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Matrix testing&lt;/strong&gt; across multiple dependency versions (Django templates)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;✅ Code Quality Gates:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Linting pipeline&lt;/strong&gt; with Ruff for import sorting and style checks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dual type checking&lt;/strong&gt; with both mypy and pyright&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code formatting&lt;/strong&gt; verification with Black&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TOML file validation&lt;/strong&gt; and sorting with toml-sort&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;📦 Automated Publishing (Package Templates):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Semantic versioning&lt;/strong&gt; with Commitizen integration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated PyPI publishing&lt;/strong&gt; on tagged releases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub releases&lt;/strong&gt; with automated changelog generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build artifact&lt;/strong&gt; caching for faster CI runs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🔒 Security &amp;amp; Quality:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dependency vulnerability scanning&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pre-commit hook validation&lt;/strong&gt; in CI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build reproducibility&lt;/strong&gt; with UV lock files&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🎨 &lt;strong&gt;Code Quality&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Pre-commit hooks automatically run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ruff&lt;/strong&gt; for linting and import sorting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Black&lt;/strong&gt; for code formatting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;toml-sort&lt;/strong&gt; for TOML file organization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type checking&lt;/strong&gt; with mypy/pyright&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Q: Why four separate templates instead of one configurable template?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;A&lt;/strong&gt;: Each template is optimized for its specific use case. A Python package has different needs than a Django API. Separate templates mean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cleaner code&lt;/strong&gt; without excessive conditionals&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster generation&lt;/strong&gt; with only relevant files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better maintenance&lt;/strong&gt; with focused concerns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easier customization&lt;/strong&gt; for specific needs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Q: Why UV instead of pip/poetry?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;A&lt;/strong&gt;: UV is incredibly fast (10-100x faster than pip) and handles both Python version management and dependency resolution. It's the future of Python package management.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q: Can I customize the generated templates?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;A&lt;/strong&gt;: Absolutely! The templates are designed to be starting points. All configuration is in standard files (&lt;code&gt;pyproject.toml&lt;/code&gt;, &lt;code&gt;settings.py&lt;/code&gt;, etc.) that you can modify as needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q: What about database migrations in Django templates?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;A&lt;/strong&gt;: The Django templates include a custom user model and initial migrations. After generation, run &lt;code&gt;scripts/manage.sh migrate&lt;/code&gt; and you're ready to go.&lt;/p&gt;




&lt;h2&gt;
  
  
  Future Roadmap
&lt;/h2&gt;

&lt;p&gt;I'm continuously improving these templates based on community feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FastAPI template&lt;/strong&gt; for modern async APIs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Next.js + Django&lt;/strong&gt; full-stack template&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes deployment&lt;/strong&gt; configurations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More cloud provider&lt;/strong&gt; integrations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Additional authentication&lt;/strong&gt; providers&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Getting Started Today
&lt;/h2&gt;

&lt;p&gt;Ready to streamline your Python development? Here's how to get started:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install cookiecutter&lt;/strong&gt;: &lt;code&gt;pip install cookiecutter&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate your project&lt;/strong&gt;: &lt;code&gt;cookiecutter gh:huynguyengl99/cookiecutter-python&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose your template&lt;/strong&gt; and configure options&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start developing&lt;/strong&gt; immediately!&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Useful Links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;📂 Repository&lt;/strong&gt;: &lt;a href="https://github.com/huynguyengl99/cookiecutter-python" rel="noopener noreferrer"&gt;github.com/huynguyengl99/cookiecutter-python&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;📖 Documentation&lt;/strong&gt;: Full README with detailed setup instructions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🐛 Issues&lt;/strong&gt;: Report bugs or request features&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;💡 Discussions&lt;/strong&gt;: Share your use cases and get help&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;These cookiecutter templates represent hundreds of hours of research, testing, and refinement to create the ideal starting point for Python projects. Whether you're building a simple CLI tool or a complex Django API, you can focus on your core business logic instead of wrestling with configuration.&lt;/p&gt;

&lt;p&gt;The templates embody modern Python best practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type safety&lt;/strong&gt; with comprehensive type checking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code quality&lt;/strong&gt; with automated formatting and linting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing excellence&lt;/strong&gt; with comprehensive test setups&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production readiness&lt;/strong&gt; with Docker and deployment configs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer experience&lt;/strong&gt; with helpful scripts and documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Give them a try for your next project. I'm confident they'll save you hours of setup time and help you ship better code faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are you waiting for? Let's build something amazing together!&lt;/strong&gt; 🚀&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have you used these templates? Found them helpful? Have suggestions for improvements? I'd love to hear about your experience! Drop a comment below or open an issue on GitHub.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>cookiecutter</category>
      <category>bestpractices</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Easy Multilingual Page (Scales to Over 50 Languages)</title>
      <dc:creator>Huy Nguyen</dc:creator>
      <pubDate>Fri, 21 Jun 2024 14:17:13 +0000</pubDate>
      <link>https://dev.to/huynguyengl99/easy-multilingual-page-scales-to-over-50-languages-3m4o</link>
      <guid>https://dev.to/huynguyengl99/easy-multilingual-page-scales-to-over-50-languages-3m4o</guid>
      <description>&lt;p&gt;Hi all,&lt;/p&gt;

&lt;p&gt;So, a few months back, I kicked off a project to create a multilingual website. Let me tell you, managing content in multiple languages is a real headache. It’s doable if you’re only dealing with 3 or 4 languages, but once you hit 30+, it’s a whole different ball game trying to keep everything updated and consistent.&lt;/p&gt;

&lt;p&gt;To make life easier, I decided to bring in a CMS for my Astro-based site. I dug into frameworks like Wagtail and Strapi since I’m familiar with Python and Node.js, but man, those were tough nuts to crack. Plus, I wanted a centralized place for all my content instead of having to jump between different pages for each language. This way, I can easily compare content across languages without getting lost.&lt;/p&gt;

&lt;p&gt;And here's the kicker: ChatGPT is shaping up to be a solid translator, but no one’s integrated it into any frameworks yet. So, with my Django and Astrowind know-how (Astrowind is this cool UI built on Astro and Tailwind, and it’s open source), I whipped up a small Django library/framework to act as a headless CMS. I also tweaked the Astrowind source to pull in content from the CMS with multilingual support.&lt;/p&gt;

&lt;p&gt;Check out this demo if you wanna see it in action:&lt;br&gt;
&lt;a href="https://django-astrowind.netlify.app/en"&gt;https://django-astrowind.netlify.app/en&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not much has changed from the original Astrowind (&lt;a href="https://astrowind.vercel.app/"&gt;https://astrowind.vercel.app/&lt;/a&gt;), except now you can switch languages on the fly, and the content is managed through a CMS with hashed caching.&lt;/p&gt;

&lt;p&gt;If you’re interested in using it, I’ve put together a tutorial to help you set it up on your own machine:&lt;br&gt;
&lt;a href="https://django-headless-cms.readthedocs.io/en/latest/quick-start.html"&gt;https://django-headless-cms.readthedocs.io/en/latest/quick-start.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope you dig it. And I hope my little project can be of some help to you guys.&lt;/p&gt;

</description>
      <category>django</category>
      <category>astrojs</category>
      <category>multilingual</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Introducing Django Headless CMS: A Powerful and Flexible CMS Solution</title>
      <dc:creator>Huy Nguyen</dc:creator>
      <pubDate>Thu, 20 Jun 2024 06:39:52 +0000</pubDate>
      <link>https://dev.to/huynguyengl99/introducing-django-headless-cms-a-powerful-and-flexible-cms-solution-82d</link>
      <guid>https://dev.to/huynguyengl99/introducing-django-headless-cms-a-powerful-and-flexible-cms-solution-82d</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Are you looking for an effortless way to create and manage a headless CMS? Look no further! I'm excited to introduce &lt;strong&gt;Django Headless CMS&lt;/strong&gt;, a robust, open-source content management system designed to simplify the process of managing and delivering content across multiple platforms. Built on Django, this package leverages the sturdy foundation of the Django framework while providing a headless approach, making it ideal for modern web applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Choose Django Headless CMS?
&lt;/h2&gt;

&lt;p&gt;Why choose Django-headless-cms over alternatives like &lt;a href="https://wagtail.org/"&gt;Wagtail&lt;/a&gt;, &lt;a href="https://www.django-cms.org/"&gt;Django-CMS&lt;/a&gt;, &lt;a href="https://strapi.io/"&gt;Strapi&lt;/a&gt;, or &lt;a href="https://www.contentful.com/"&gt;Contentful&lt;/a&gt;?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Headless CMS with minimal configuration&lt;/strong&gt;: Unlike Wagtail and Django-CMS, which are primarily headed CMS solutions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive UI&lt;/strong&gt;: Preferred over Strapi for its user interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python &amp;amp; Django-based&lt;/strong&gt;: Built on a robust framework with numerous extensions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open Source&lt;/strong&gt;: Unlike Contentful and other paid services, it allows you to self-host your CMS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration&lt;/strong&gt;: Easily integrates with many existing Python and Django libraries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centralized multi-language support&lt;/strong&gt;: Reduces redundancy and allows different content across multiple languages.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;p&gt;Django Headless CMS comes packed with features to enhance your content management experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Schema Migrations&lt;/strong&gt;: Manage content schema as database migrations, making it easier to sync from development to production environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versioning Content&lt;/strong&gt;: Revert to any previously saved version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish/Draft Content&lt;/strong&gt;: Manage published and draft content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Markdown Editor Support&lt;/strong&gt;: Enhanced content editing experience, useful for Posts/Articles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-language Support&lt;/strong&gt;: Even for Markdown fields.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto Translate/Force Re-translate&lt;/strong&gt;: Use ChatGPT or build your own translation interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recursive Actions&lt;/strong&gt;: Apply actions like Publish, Translate, and Force Re-translate to referenced objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimized Queries&lt;/strong&gt;: Auto prefetch and select related queries for optimization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filter Published Objects&lt;/strong&gt;: Easily filter to show only published content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto Admin&lt;/strong&gt;: Simplify admin page setup with features like:

&lt;ul&gt;
&lt;li&gt;Sortable inline Many-to-Many (M2M) relationships.&lt;/li&gt;
&lt;li&gt;Sortable generic inlines.&lt;/li&gt;
&lt;li&gt;Display publish status of child objects.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto Serializer&lt;/strong&gt;: Simplify serializer creation, including nested relations. Override specific serializers as needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rapid API Development&lt;/strong&gt;: Build APIs (Views/Viewsets) quickly and easily with auto serializers and optimized queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy Data Import/Export&lt;/strong&gt;: Use the admin interface or management commands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-generated API Documentation &amp;amp; Playground&lt;/strong&gt;: Automatically generate API documentation and an interactive playground.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;

&lt;p&gt;To get started with Django Headless CMS, follow the tutorial from the docs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://django-headless-cms.readthedocs.io/en/latest/quick-start.html"&gt;Quick Start Guide&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Want to see a quick demo? By the end of this tutorial, you will have a CMS that can be used to build a multi-lingual page that looks like this: &lt;a href="https://django-astrowind.netlify.app/en"&gt;Django Astrowind Demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Publish/Unpublish/Recursively publish:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwx3axvu100imt07zqds5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwx3axvu100imt07zqds5.png" alt="Image description" width="800" height="123"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-language &amp;amp; markdown editor:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7xvglf5zgt6099ou026h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7xvglf5zgt6099ou026h.png" alt="Image description" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F126c91f21w3dvv2nkeg9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F126c91f21w3dvv2nkeg9.png" alt="Image description" width="800" height="656"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Drag-to-sort related items:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftto50ju0e3cft38haukn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftto50ju0e3cft38haukn.png" alt="Image description" width="800" height="560"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Auto-translate to multiple languages:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxcm4evb8lcq38eti7nge.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxcm4evb8lcq38eti7nge.png" alt="Image description" width="800" height="60"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;And other cool features. Read more in the docs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;After experimenting with various CMS frameworks, I built Django Headless CMS and Django Astrowind to meet my specific needs and address issues faced by others in the community.&lt;/p&gt;

&lt;p&gt;For more information, explore the &lt;a href="https://django-headless-cms.readthedocs.io/"&gt;Django Headless CMS documentation&lt;/a&gt; and the &lt;a href="https://github.com/huynguyengl99/django-astrowind"&gt;Django Astrowind repository&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>django</category>
      <category>cms</category>
      <category>opensource</category>
      <category>python</category>
    </item>
  </channel>
</rss>
