Python Django Social Media App From Scratch

Written by

in

Building a Python Django social media app from scratch may sound like a daunting challenge, but with the right roadmap you can turn a simple idea into a fully‑featured platform that rivals today’s biggest networks. In this guide we’ll walk through every critical step—setting up the project, designing the data model, implementing authentication, creating posts, handling media uploads, and adding real‑time features—all while keeping SEO best practices in mind so your tutorial climbs the search rankings.

Why Choose Django for a Social Media App?

Django’s “batteries‑included” philosophy makes it an ideal foundation for a social media platform. It provides:

  • Robust ORM for rapid database modeling.
  • Built‑in User authentication and permission handling.
  • Scalable architecture with reusable apps.
  • Excellent community support and a wealth of third‑party packages (e.g., django‑rest‑framework, channels).

Project Setup: Laying the Groundwork

1. Create a Virtual Environment

python -m venv env
source env/bin/activate  # On Windows use `env\Scripts\activate`
pip install --upgrade pip

2. Install Django and Essential Packages

pip install django djangorestframework pillow django‑crispy‑forms
pip install channels  # For WebSocket support
pip install psycopg2-binary  # PostgreSQL driver (recommended for production)

3. Start the Project and Core Apps

django-admin startproject socialsite
cd socialsite
python manage.py startapp accounts
python manage.py startapp posts
python manage.py startapp notifications

Designing the Data Model

A solid schema is the backbone of any social network. Below is a concise model overview that balances simplicity with extensibility.

accounts/models.py

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

class User(AbstractUser):
    bio = models.TextField(blank=True, max_length=500)
    avatar = models.ImageField(upload_to='avatars/', blank=True, null=True)
    followers = models.ManyToManyField('self',
                                      symmetrical=False,
                                      related_name='following',
                                      blank=True)

posts/models.py

from django.db import models
from accounts.models import User

class Post(models.Model):
    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
    content = models.TextField(max_length=280)  # Twitter‑style limit
    image = models.ImageField(upload_to='posts/', blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    likes = models.ManyToManyField(User, related_name='liked_posts', blank=True)

    class Meta:
        ordering = ['-created_at']

notifications/models.py

from django.db import models
from accounts.models import User
from posts.models import Post

class Notification(models.Model):
    recipient = models.ForeignKey(User, on_delete=models.CASCADE, related_name='notifications')
    sender = models.ForeignKey(User, on_delete=models.CASCADE)
    post = models.ForeignKey(Post, on_delete=models.CASCADE, null=True, blank=True)
    verb = models.CharField(max_length=255)  # e.g., "liked", "commented"
    read = models.BooleanField(default=False)
    timestamp = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['-timestamp']

Implementing User Authentication & Profiles

Django’s authentication system already handles login, logout, and password management. We’ll extend it with a custom user model and a sleek registration flow.

Key Steps

  1. Set AUTH_USER_MODEL = 'accounts.User' in settings.py.
  2. Create registration and profile forms using django‑crispy‑forms for a modern UI.
  3. Use LoginView and LogoutView from django.contrib.auth.views for quick setup.
  4. Protect routes with @login_required or LoginRequiredMixin.

Building the Core Features

Posting, Liking, and Commenting

Leverage Django REST Framework (DRF) to expose a clean JSON API that your front‑end (or mobile app) can consume.

# posts/serializers.py
from rest_framework import serializers
from .models import Post

class PostSerializer(serializers.ModelSerializer):
    author_username = serializers.ReadOnlyField(source='author.username')
    likes_count = serializers.SerializerMethodField()

    class Meta:
        model = Post
        fields = ['id', 'author', 'author_username', 'content', 'image',
                  'created_at', 'likes_count']

    def get_likes_count(self, obj):
        return obj.likes.count()

For liking a post, create a simple endpoint that toggles the relationship:

# posts/views.py
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from .models import Post

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def toggle_like(request, pk):
    post = Post.objects.get(pk=pk)
    user = request.user
    if user in post.likes.all():
        post.likes.remove(user)
        liked = False
    else:
        post.likes.add(user)
        liked = True
    return Response({'liked': liked, 'likes_count': post.likes.count()})

Real‑Time Notifications with Django Channels

Instant feedback keeps users engaged. With channels you can push notifications over WebSockets.

# notifications/consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer

class NotificationConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        if self.scope["user"].is_anonymous:
            await self.close()
        else:
            self.group_name = f'notifications_{self.scope["user"].id}'
            await self.channel_layer.group_add(self.group_name, self.channel_name)
            await self.accept()

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(self.group_name, self.channel_name)

    async def send_notification(self, event):
        await self.send(text_data=json.dumps(event['content']))

Whenever a like or comment occurs, trigger the consumer:

# posts/signals.py
from django.dispatch import receiver
from django.db.models.signals import m2m_changed
from notifications.models import Notification
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer

@receiver(m2m_changed, sender=Post.likes.through)
def create_like_notification(sender, instance, action, pk_set, **kwargs):
    if action == "post_add":
        liker = User.objects.get(pk=list(pk_set)[0])
        Notification.objects.create(
            recipient=instance.author,
            sender=liker,
            post=instance,
            verb='liked your post'
        )
        channel_layer = get_channel_layer()
        async_to_sync(channel_layer.group_send)(
            f'notifications_{instance.author.id}',
            {
                'type': 'send_notification',
                'content': {
                    'message': f'{liker.username} liked your post',
                    'post_id': instance.id
                }
            }
        )

Front‑End Integration

While Django can render templates with {% static %} and {% url %}, many developers pair it with a JavaScript framework (React, Vue, or Alpine.js) for a smoother SPA experience. Below is a minimal example using vanilla JavaScript to fetch posts and display live notifications.

<!-- templates/home.html -->
<div id="feed"></div>
<div id="notifications"></div>

<script>
async function loadFeed() {
    const resp = await fetch('/api/posts/');
    const posts = await resp.json();
    const feed = document.getElementById('feed');
    feed.innerHTML = posts.map(p => `
        <div class="post">
            <strong>${p.author_username}</strong>: ${p.content}
            <button onclick="toggleLike(${p.id})">❤️ ${p.likes_count}</button>
        </div>
    `).join('');
}
async function toggleLike(postId) {
    await fetch(`/api/posts/${postId}/like/`, {method: 'POST', headers: {'X-CSRFToken': getCookie('csrftoken')}});
    loadFeed();
}
loadFeed();

// WebSocket for notifications
const socket = new WebSocket('ws://' + window.location.host + '/ws/notifications/');
socket.onmessage = function(e) {
    const data = JSON.parse(e.data);
    const list = document.getElementById('notifications');
    const item = document.createElement('div');
    item.textContent = data.message;
    list.prepend(item);
};
</script>

Deploying Your Django Social Media App

Production readiness involves a few essential steps:

  • Database: Switch to PostgreSQL or MySQL for reliability.
  • Static & Media Files: Serve via WhiteNoise or a CDN (e.g., Amazon S3).
  • Security: Set

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *