In this post we use Python inheritance to create models of different types, that extend a Post model. We then create a ListView that lists all posts and use this view to show each post based on its type, whether it is a text post, a photo, a video, or voice.
Creating a Django application that supports multiple content types—text, photos, videos, and audio posts—can be a powerful way to enhance user engagement and provide flexibility in content creation. This tutorial walks through building an Album app where each post can be a text entry, photo, video, or voice recording. You’ll learn to set up models, configure views, and use Django templates to render each type of post uniquely.
Step 1: Setting Up Models
To manage different post types, we’ll create a base Post model and specific models for each media type (photo, video, voice). Each specific model will inherit from Post, allowing us to organize shared fields (like author and content) while customizing attributes based on the post type.
Here’s what our models look like:
from django.db import models from django.conf import settings CustomUser = settings.AUTH_USER_MODEL class Post(models.Model): author = models.ForeignKey(CustomUser, on_delete=models.CASCADE) content = models.TextField(max_length=10000) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def __str__(self): return f"Post by {self.author} on {self.created_at:%Y-%m-%d}" class Photo(Post): image = models.ImageField(upload_to="photos/") def __str__(self): return f"Photo by {self.author} on {self.created_at:%Y-%m-%d}" class Video(Post): video_file = models.FileField(upload_to="videos/") def __str__(self): return f"Video by {self.author} on {self.created_at:%Y-%m-%d}" class Voice(Post): audio = models.FileField(upload_to="voices/") def __str__(self): return f"Voice by {self.author} on {self.created_at:%Y-%m-%d}"
In this setup:
- Post is the base model that all other types inherit.
- Photo, Video, and Voice models each have their own specific fields (image, video_file, and audio, respectively).
Step 2: Creating a PostListView to Display All Posts
We’ll use Django’s ListView to create a page that displays all posts, ordering them by creation date. Here’s how our view class will look:
class PostListView(ListView): model = Post context_object_name = "posts" paginate_by = 12 def get_queryset(self): # Get all types of posts and order them by created_at return Post.objects.select_related("photo", "video", "voice").order_by( "-created_at" )
The get_queryset method uses select_related to optimize database queries for subclass instances (photo, video, and voice), and orders them by created_at so that the newest posts appear first.
Step 3: Designing the Template to Display Different Post Types
In post_list.html, we’ll use template logic to differentiate between the types of posts (text, photo, video, or voice) and display each type with the appropriate HTML structure. This approach ensures that images, videos, and audio files are rendered correctly based on the post type.
Here’s the template code:
<ul> {% for post in posts %} <li> {% if post.photo %} <div class="photo-post"> <div>By @{{ post.author }} on {{ post.created_at }}</div> {% if post.photo.image %} <img src="{{ post.photo.image.url }}" alt="Photo By @{{ post.author }} on {{ post.created_at }}" /> {% endif %} <p>{{ post.content|linebreaks }}</p> </div> {% elif post.video.video_file %} <div class="video-post"> <div>By @{{ post.author }} on {{ post.created_at }}</div> <video controls> <source src="{{ post.video.video_file.url }}" type="video/mp4" /> </video> <p>{{ post.content|linebreaks }}</p> </div> {% elif post.voice %} <div class="voice-post"> <div>By @{{ post.author }} on {{ post.created_at }}</div> <audio controls> <source src="{{ post.voice.audio.url }}" type="audio/mpeg" /> </audio> <p>{{ post.content|linebreaks }}</p> </div> {% else %} <div class="text-post"> <div>By @{{ post.author }} on {{ post.created_at }}</div> <p>{{ post.content|linebreaks }}</p> </div> {% endif %} </li> {% endfor %} </ul>
Explanation of the Template Code:
- Photo Post: If post.photo is detected, it displays the image and content.
- Video Post: If post.video is detected, it renders a <video> tag with controls for playback.
- Voice Post: If post.voice is detected, it renders an <audio> tag with controls.
- Text Post: If none of the above are true, it assumes it’s a text-only post.
Step 4: Enhancing the User Experience with CSS (Optional)
To improve readability and design, consider adding CSS classes like .photo-post, .video-post, .voice-post, and .text-post. These styles can help each type of post stand out.
.photo-post, .video-post, .voice-post, .text-post { margin-bottom: 20px; padding: 10px; border: 1px solid #ccc; border-radius: 5px; } .photo-post img, .video-post video { max-width: 100%; height: auto; display: block; margin-top: 10px; }
Wrapping Up
By using Django’s model inheritance and powerful template logic,
we’ve built an efficient album application that supports diverse content
types. This structure offers users a flexible way to share content
while keeping the implementation streamlined for easier maintenance and
scalability.