Search code examples
pythondjangomodel

Django - Handle Image and Video posts as one type of post


For the sake of brevity, let's say we have the following two classes in models.py:

class ImagePost(models.Model):
    image = models.ImageField(...)
    # other Image related fields

class VideoPost(models.Model):
    video = models.FileField(...)
    # other Video related fields

In the urls.py, I have urls that can be used to query either video or image posts. So, I can query them separately. But that is not what I want.

What I want is the following functionality: When my application connects to the Django server, it should be able to query both post types such that the resulting queried data contains both types (e.g. sorted based on the timestamps). I want to display all types based on their creation time.

My first thought was to put everything from both into one class like the following:

class Post(models.Model):
    image = ...
    # all image related fields

    video = ...
    # all video related fields

But that class has so many entries and somehow I do not like that solution.

Does somebody have another solution that can be used in such a case ?


Solution

  • While it sometimes results in confusion, you might be looking for model inheritance.

    from django.db import models
    
    
    class Post(models.Model):
        headline = models.TextField()
    
        def __str__(self):
            return self.headline
    
    
    class VideoPost(Post):
        video = models.BooleanField(default=True)
    
    
    class ImagePost(Post):
        image = models.BooleanField(default=True)
    

    This enables querying all posts, though you'll get Post objects back from queries against Post.objects (note that I did not use an abstract base class here because that would not provide the Post.objects manager, which I assume you'll want to use). Example:

    >>> from mt.models import *
    >>> ImagePost(headline="Tasty images.").save()
    >>> VideoPost(headline="Hooray for video!").save()
    >>> Post.objects.all()
    <QuerySet [<Post: Tasty images.>, <Post: Hooray for video!>]>
    >>> i = Post.objects.all()[0]
    >>> i
    <Post: Tasty images.>
    >>> i.imagepost
    <ImagePost: Tasty images.>
    >>> i.imagepost.image
    True
    

    Be very careful when considering this. The linked documentation goes into detail on a lot of points that are worth thinking about when you're deciding whether this is a good approach for your use case.