$ cat /posts/project-social-media-platform-with-django-channels.md

Project: Social Media Platform with Django Channels

drwxr-xr-x2026-01-245 min0 views
Project: Social Media Platform with Django Channels

Building complete social media platform demonstrates Django advanced features implementing user profiles, posts, likes, comments, real-time notifications, and messaging with Django Channels maintaining production-ready architecture for interactive web applications. Social media platforms require complex functionality including user relationships (followers/following), activity feeds, real-time updates through WebSockets, content moderation, and notification systems creating sophisticated requirements beyond traditional request-response patterns. Traditional Django handles HTTP requests synchronously while WebSocket connections maintain persistent bidirectional communication enabling instant updates when users receive messages, notifications, or see new posts appearing in feeds. Without real-time features, users must refresh pages manually to see updates creating poor user experience compared to modern applications providing instant feedback. This comprehensive tutorial builds fully-functional social platform from scratch including project setup with Channels and Redis, user profile system with avatars and bios, post creation with images and captions, like and comment functionality, follower/following relationships, activity feed showing followed users' posts, real-time notifications using WebSockets, direct messaging between users, notification system for likes and comments, search functionality finding users and posts, and admin interface managing content moderation. Real-world features include privacy settings controlling post visibility, blocking users preventing unwanted interactions, reporting inappropriate content, hashtag support for discovery, mention system tagging users in posts, and content recommendations. Project demonstrates Django 6.0 best practices including models with proper relationships, WebSocket consumers handling real-time events, channel layers broadcasting messages, class-based views maintaining code reusability, security measures protecting user data, and scalable architecture supporting thousands of concurrent connections. This hands-on guide provides complete code building professional social media platform from initial setup through real-time features and production deployment teaching practical Django development maintaining performance throughout.

Project Setup with Channels

Project setup creates Django environment installing Channels for WebSocket support, Redis for channel layer, and configuring ASGI for asynchronous handling. Understanding Channels architecture integrated with Django project structure enables building real-time applications maintaining scalability.

pythonsocial_setup.py
# Django 6.0 Social Media Project Setup

# Create virtual environment
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate

# Install dependencies
pip install Django==6.0
pip install channels==4.0.0
pip install channels-redis
pip install Pillow  # Image handling
pip install django-crispy-forms crispy-bootstrap5

# Install Redis (required for channel layer)
# Ubuntu/Debian: sudo apt-get install redis-server
# macOS: brew install redis
# Start Redis: redis-server

# Create project
django-admin startproject social_project
cd social_project

# Create apps
python manage.py startapp accounts
python manage.py startapp posts
python manage.py startapp notifications
python manage.py startapp chat

# Project structure:
# social_project/
# β”œβ”€β”€ manage.py
# β”œβ”€β”€ social_project/
# β”‚   β”œβ”€β”€ asgi.py  # ASGI configuration
# β”‚   β”œβ”€β”€ settings.py
# β”‚   β”œβ”€β”€ urls.py
# β”‚   └── routing.py  # WebSocket routing
# β”œβ”€β”€ accounts/  # User profiles
# β”œβ”€β”€ posts/     # Posts, likes, comments
# β”œβ”€β”€ notifications/  # Real-time notifications
# └── chat/      # Direct messaging

# Configure settings.py
INSTALLED_APPS = [
    'daphne',  # Must be first for Channels
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    
    # Third-party
    'channels',
    'crispy_forms',
    'crispy_bootstrap5',
    
    # Local apps
    'accounts',
    'posts',
    'notifications',
    'chat',
]

# ASGI application
ASGI_APPLICATION = 'social_project.asgi.application'

# Channel layers configuration
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            'hosts': [('127.0.0.1', 6379)],
        },
    },
}

# Media files
import os
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

# ASGI configuration
# social_project/asgi.py

import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
import social_project.routing

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'social_project.settings')

application = ProtocolTypeRouter({
    'http': get_asgi_application(),
    'websocket': AuthMiddlewareStack(
        URLRouter(
            social_project.routing.websocket_urlpatterns
        )
    ),
})

# WebSocket routing
# social_project/routing.py

from django.urls import path
from notifications import consumers as notification_consumers
from chat import consumers as chat_consumers

websocket_urlpatterns = [
    path('ws/notifications/', notification_consumers.NotificationConsumer.as_asgi()),
    path('ws/chat/<int:user_id>/', chat_consumers.ChatConsumer.as_asgi()),
]

User Profiles and Relationships

User models extend Django's User with Profile storing additional information and Follow model tracking follower/following relationships with symmetrical connections. Understanding user relationships integrated with Django relationships enables building social graphs maintaining data integrity.

pythonsocial_models.py
# User profile and relationship models
# accounts/models.py

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(max_length=500, blank=True)
    avatar = models.ImageField(upload_to='avatars/', blank=True, null=True)
    location = models.CharField(max_length=100, blank=True)
    website = models.URLField(blank=True)
    birth_date = models.DateField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    
    def __str__(self):
        return f'{self.user.username} Profile'
    
    @property
    def followers_count(self):
        return self.user.followers.count()
    
    @property
    def following_count(self):
        return self.user.following.count()

# Auto-create profile for new users
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

class Follow(models.Model):
    follower = models.ForeignKey(User, on_delete=models.CASCADE, related_name='following')
    following = models.ForeignKey(User, on_delete=models.CASCADE, related_name='followers')
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        unique_together = ['follower', 'following']
        ordering = ['-created_at']
    
    def __str__(self):
        return f'{self.follower.username} follows {self.following.username}'

# Post models
# posts/models.py

from django.db import models
from django.contrib.auth.models import User

class Post(models.Model):
    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
    content = models.TextField(max_length=500)
    image = models.ImageField(upload_to='posts/', blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        ordering = ['-created_at']
    
    def __str__(self):
        return f'Post by {self.author.username}'
    
    @property
    def likes_count(self):
        return self.likes.count()
    
    @property
    def comments_count(self):
        return self.comments.count()

class Like(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='likes')
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        unique_together = ['user', 'post']
    
    def __str__(self):
        return f'{self.user.username} likes {self.post.id}'

class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    content = models.TextField(max_length=300)
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        ordering = ['created_at']
    
    def __str__(self):
        return f'Comment by {self.author.username}'

# Run migrations
python manage.py makemigrations
python manage.py migrate

Views and Activity Feed

Views implement social features with activity feed showing followed users' posts, profile pages displaying user information and posts, follow/unfollow functionality managing relationships, and post CRUD operations. Understanding view implementation enables building complete social interactions maintaining user engagement.

pythonsocial_views.py
# Social media views
# posts/views.py

from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.db.models import Q
from .models import Post, Like, Comment
from .forms import PostForm, CommentForm
from accounts.models import Follow

@login_required
def feed(request):
    # Get posts from followed users and own posts
    following_users = request.user.following.values_list('following', flat=True)
    posts = Post.objects.filter(
        Q(author__in=following_users) | Q(author=request.user)
    ).select_related('author').prefetch_related('likes', 'comments')
    
    if request.method == 'POST':
        form = PostForm(request.POST, request.FILES)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.save()
            return redirect('posts:feed')
    else:
        form = PostForm()
    
    return render(request, 'posts/feed.html', {
        'posts': posts,
        'form': form
    })

@login_required
def like_post(request, post_id):
    post = get_object_or_404(Post, id=post_id)
    
    like, created = Like.objects.get_or_create(
        user=request.user,
        post=post
    )
    
    if not created:
        like.delete()
    else:
        # Send notification
        from notifications.models import Notification
        if post.author != request.user:
            Notification.objects.create(
                recipient=post.author,
                sender=request.user,
                notification_type='like',
                post=post
            )
    
    return redirect(request.META.get('HTTP_REFERER', 'posts:feed'))

@login_required
def add_comment(request, post_id):
    post = get_object_or_404(Post, id=post_id)
    
    if request.method == 'POST':
        form = CommentForm(request.POST)
        if form.is_valid():
            comment = form.save(commit=False)
            comment.post = post
            comment.author = request.user
            comment.save()
            
            # Send notification
            from notifications.models import Notification
            if post.author != request.user:
                Notification.objects.create(
                    recipient=post.author,
                    sender=request.user,
                    notification_type='comment',
                    post=post,
                    comment=comment
                )
    
    return redirect(request.META.get('HTTP_REFERER', 'posts:feed'))

# User profile views
# accounts/views.py

from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from .models import Follow
from posts.models import Post

@login_required
def profile(request, username):
    user = get_object_or_404(User, username=username)
    posts = Post.objects.filter(author=user)
    is_following = Follow.objects.filter(
        follower=request.user,
        following=user
    ).exists()
    
    return render(request, 'accounts/profile.html', {
        'profile_user': user,
        'posts': posts,
        'is_following': is_following
    })

@login_required
def follow_user(request, user_id):
    user_to_follow = get_object_or_404(User, id=user_id)
    
    if user_to_follow != request.user:
        follow, created = Follow.objects.get_or_create(
            follower=request.user,
            following=user_to_follow
        )
        
        if not created:
            follow.delete()
        else:
            # Send notification
            from notifications.models import Notification
            Notification.objects.create(
                recipient=user_to_follow,
                sender=request.user,
                notification_type='follow'
            )
    
    return redirect('accounts:profile', username=user_to_follow.username)

@login_required
def search(request):
    query = request.GET.get('q', '')
    
    if query:
        users = User.objects.filter(
            Q(username__icontains=query) |
            Q(first_name__icontains=query) |
            Q(last_name__icontains=query)
        )[:20]
        
        posts = Post.objects.filter(
            content__icontains=query
        )[:20]
    else:
        users = []
        posts = []
    
    return render(request, 'search.html', {
        'users': users,
        'posts': posts,
        'query': query
    })

Real-Time Notifications with WebSockets

WebSocket consumers handle real-time notifications sending instant updates when users receive likes, comments, or new followers without page refresh. Understanding WebSocket implementation enables building responsive applications maintaining live connections with users.

pythonrealtime_notifications.py
# Notification model
# notifications/models.py

from django.db import models
from django.contrib.auth.models import User
from posts.models import Post, Comment

class Notification(models.Model):
    NOTIFICATION_TYPES = [
        ('like', 'Like'),
        ('comment', 'Comment'),
        ('follow', 'Follow'),
        ('mention', 'Mention'),
    ]
    
    recipient = models.ForeignKey(User, on_delete=models.CASCADE, related_name='notifications')
    sender = models.ForeignKey(User, on_delete=models.CASCADE, related_name='sent_notifications')
    notification_type = models.CharField(max_length=20, choices=NOTIFICATION_TYPES)
    post = models.ForeignKey(Post, on_delete=models.CASCADE, null=True, blank=True)
    comment = models.ForeignKey(Comment, on_delete=models.CASCADE, null=True, blank=True)
    read = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        ordering = ['-created_at']
    
    def __str__(self):
        return f'{self.notification_type} from {self.sender.username}'

# WebSocket consumer for notifications
# notifications/consumers.py

import json
from channels.generic.websocket import AsyncWebsocketConsumer
from channels.db import database_sync_to_async
from django.contrib.auth.models import User

class NotificationConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.user = self.scope['user']
        
        if self.user.is_authenticated:
            self.group_name = f'notifications_{self.user.id}'
            
            # Join notification group
            await self.channel_layer.group_add(
                self.group_name,
                self.channel_name
            )
            
            await self.accept()
            
            # Send unread count on connect
            unread_count = await self.get_unread_count()
            await self.send(text_data=json.dumps({
                'type': 'unread_count',
                'count': unread_count
            }))
        else:
            await self.close()
    
    async def disconnect(self, close_code):
        if hasattr(self, 'group_name'):
            await self.channel_layer.group_discard(
                self.group_name,
                self.channel_name
            )
    
    async def receive(self, text_data):
        data = json.loads(text_data)
        
        if data.get('action') == 'mark_read':
            notification_id = data.get('notification_id')
            await self.mark_notification_read(notification_id)
    
    async def notification_message(self, event):
        await self.send(text_data=json.dumps({
            'type': 'notification',
            'notification': event['notification']
        }))
    
    @database_sync_to_async
    def get_unread_count(self):
        from .models import Notification
        return Notification.objects.filter(
            recipient=self.user,
            read=False
        ).count()
    
    @database_sync_to_async
    def mark_notification_read(self, notification_id):
        from .models import Notification
        Notification.objects.filter(
            id=notification_id,
            recipient=self.user
        ).update(read=True)

# Send notification helper
# notifications/utils.py

from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync

def send_notification(recipient, notification_data):
    channel_layer = get_channel_layer()
    group_name = f'notifications_{recipient.id}'
    
    async_to_sync(channel_layer.group_send)(
        group_name,
        {
            'type': 'notification_message',
            'notification': notification_data
        }
    )

# Frontend WebSocket connection
# templates/base.html

<script>
const notificationSocket = new WebSocket(
    'ws://' + window.location.host + '/ws/notifications/'
);

notificationSocket.onmessage = function(e) {
    const data = JSON.parse(e.data);
    
    if (data.type === 'notification') {
        // Show notification
        showNotification(data.notification);
        updateNotificationBadge();
    } else if (data.type === 'unread_count') {
        updateNotificationBadge(data.count);
    }
};

function showNotification(notification) {
    // Display notification in UI
    const notificationHtml = `
        <div class="notification">
            <strong>${notification.sender}</strong> ${notification.message}
        </div>
    `;
    document.getElementById('notifications-list').innerHTML += notificationHtml;
}

function updateNotificationBadge(count) {
    const badge = document.getElementById('notification-badge');
    if (count > 0) {
        badge.textContent = count;
        badge.style.display = 'inline';
    } else {
        badge.style.display = 'none';
    }
}
</script>

Direct Messaging System

Direct messaging enables users sending private messages through WebSocket connections maintaining chat history with database persistence. Understanding chat implementation enables building real-time communication features maintaining message delivery and read receipts.

pythonmessaging_system.py
# Chat models
# chat/models.py

from django.db import models
from django.contrib.auth.models import User

class Message(models.Model):
    sender = models.ForeignKey(User, on_delete=models.CASCADE, related_name='sent_messages')
    recipient = models.ForeignKey(User, on_delete=models.CASCADE, related_name='received_messages')
    content = models.TextField()
    read = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        ordering = ['created_at']
    
    def __str__(self):
        return f'Message from {self.sender.username} to {self.recipient.username}'

# Chat consumer
# chat/consumers.py

import json
from channels.generic.websocket import AsyncWebsocketConsumer
from channels.db import database_sync_to_async
from django.contrib.auth.models import User

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.user = self.scope['user']
        self.other_user_id = self.scope['url_route']['kwargs']['user_id']
        
        # Create unique room name
        users = sorted([self.user.id, int(self.other_user_id)])
        self.room_name = f'chat_{users[0]}_{users[1]}'
        
        await self.channel_layer.group_add(
            self.room_name,
            self.channel_name
        )
        
        await self.accept()
        
        # Load chat history
        messages = await self.get_messages()
        await self.send(text_data=json.dumps({
            'type': 'chat_history',
            'messages': messages
        }))
    
    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(
            self.room_name,
            self.channel_name
        )
    
    async def receive(self, text_data):
        data = json.loads(text_data)
        message_content = data['message']
        
        # Save message to database
        message = await self.save_message(message_content)
        
        # Broadcast to room
        await self.channel_layer.group_send(
            self.room_name,
            {
                'type': 'chat_message',
                'message': {
                    'id': message.id,
                    'sender': self.user.username,
                    'content': message_content,
                    'created_at': message.created_at.isoformat()
                }
            }
        )
    
    async def chat_message(self, event):
        await self.send(text_data=json.dumps({
            'type': 'message',
            'message': event['message']
        }))
    
    @database_sync_to_async
    def save_message(self, content):
        from .models import Message
        other_user = User.objects.get(id=self.other_user_id)
        return Message.objects.create(
            sender=self.user,
            recipient=other_user,
            content=content
        )
    
    @database_sync_to_async
    def get_messages(self):
        from .models import Message
        other_user = User.objects.get(id=self.other_user_id)
        
        messages = Message.objects.filter(
            models.Q(sender=self.user, recipient=other_user) |
            models.Q(sender=other_user, recipient=self.user)
        ).order_by('created_at')[:50]
        
        return [{
            'id': msg.id,
            'sender': msg.sender.username,
            'content': msg.content,
            'created_at': msg.created_at.isoformat()
        } for msg in messages]

# Chat view
# chat/views.py

from django.shortcuts import render, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User

@login_required
def chat_room(request, user_id):
    other_user = get_object_or_404(User, id=user_id)
    return render(request, 'chat/room.html', {
        'other_user': other_user
    })
FeatureTechnologyPurposeUser Benefit
User ProfilesOneToOne relationshipStore user infoPersonalized profiles
Follow SystemMany-to-Many through modelUser relationshipsSocial connections
Activity FeedFiltered QuerySetsShow relevant postsEngaging content
Real-time NotificationsDjango Channels + WebSocketsInstant updatesLive interaction
Direct MessagingWebSocket consumersPrivate communicationUser engagement
Social media platform demonstrates Django Channels for real-time features maintaining WebSocket connections. Build upon this foundation adding features like stories, live streaming, video posts, and group chats maintaining scalable architecture handling thousands of concurrent connections integrated with Celery for background tasks.

Social Platform Best Practices

  • Implement privacy settings: Allow users controlling post visibility and profile access maintaining privacy
  • Use select_related/prefetch_related: Optimize database queries preventing N+1 problems maintaining performance
  • Add content moderation: Implement reporting and blocking features preventing abuse maintaining community safety
  • Optimize WebSocket connections: Use channel layers efficiently handling concurrent connections at scale
  • Implement pagination: Add infinite scroll or pagination preventing loading excessive data maintaining speed
  • Cache user feeds: Use Redis caching for frequently accessed feeds reducing database load
  • Handle connection failures: Implement reconnection logic maintaining reliability when WebSocket drops
  • Add rate limiting: Prevent spam with rate limits on posts, messages, and follows maintaining quality
  • Monitor performance: Track WebSocket connections, message throughput, and database queries optimizing bottlenecks
  • Test real-time features: Write tests for WebSocket consumers ensuring reliability

Conclusion

Building complete social media platform demonstrates Django Channels for real-time features implementing WebSocket connections maintaining persistent bidirectional communication enabling instant updates when users receive notifications, messages, or see new posts appearing in feeds without refresh. Project setup installs Channels for WebSocket support with Redis providing channel layer enabling message broadcasting across server instances maintaining scalability. User models extend Django's User with Profile storing additional information and Follow model tracking follower/following relationships with unique_together constraint preventing duplicate follows maintaining data integrity. Activity feed queries posts from followed users using QuerySet filtering with select_related optimizing database access while views handle post creation, likes, comments, and follow functionality integrating business logic maintaining clean separation. Real-time notifications use WebSocket consumers connecting users to notification groups sending instant updates when receiving likes, comments, or new followers with channel layer broadcasting messages across connections maintaining live updates. Direct messaging implements chat functionality with Message model persisting chat history and ChatConsumer handling WebSocket connections creating unique room names sorting user IDs maintaining bidirectional communication with message broadcasting to room members. Features include user profiles with avatars and bios, post creation with images, like and comment functionality with notifications, follower/following relationships, activity feed showing relevant posts, real-time notifications through WebSockets, direct messaging between users, search finding users and posts, and content moderation with reporting. Best practices include implementing privacy settings controlling visibility, using select_related preventing N+1 queries, adding content moderation with reporting and blocking, optimizing WebSocket connections handling scale, implementing pagination preventing excessive loading, caching user feeds reducing database load, handling connection failures with reconnection logic, adding rate limiting preventing spam, monitoring performance tracking metrics, and testing real-time features ensuring reliability. Understanding complete social platform development from user relationships through real-time messaging integrated with Django Channels, WebSockets, Redis, and database optimization provides practical foundation building production-ready social applications serving thousands of concurrent users maintaining performance and reliability throughout application lifecycle.

$ cat /comments/ (0)

new_comment.sh

// Email hidden from public

>_

$ cat /comments/

// No comments found. Be the first!

[session] guest@{codershandbook}[timestamp] 2026

Navigation

Connect

Subscribe

// 2026 {Coders Handbook}. EOF.