Parker
Parker

Reputation: 8851

Proper/most efficient way to handle Django models and relational data

I'm curious about what the best way to handle models in Django is. Let's say you want to make an app that deals with TV Show listings. One way to handle the model would be

class TVShow(models.Model)  
     channel = models.CharField()  
     show_name = models.CharField()  
     season = models.CharField()  
     episode = models.CharField()

Which has the advantage of everything being packed neatly. However, if I want to display a list of all of the channels, or all of the show_names, I would have to go through the TVSHow objects and remove duplicates

On the other hand one could

class CommonModel(models.Model)
    name = models.CharField()

    class Meta:
        Abstract = True

class Channel(CommonModel)
    show_name = models.ManyToMany(ShowName)

class ShowName(CommonModel)
    seasons = models.ManyToMany(Seasons)

class Season(CommonModel)
    episodes = models.ManyToMany(Episodes)

class Episode(CommonModel)

This would make it easy to show all of the ShowNames or all of the Channels, without having to worry about unrelated data. However, it would be much harder to see what Channel a show is, unless you map back as well

Is there a "pythonic" or Django preferred way to do this? Are there any advantages in terms of space, speed, etc?

Thanks!

Upvotes: 0

Views: 359

Answers (2)

Victor Gavro
Victor Gavro

Reputation: 1407

Preferred way to use normalized database structure unless it's performance-related, it will give you ability to make more complex queries in your code easier. ForeignKey and ManyToManyField accepts 'related_name' argument.

class Channel(models.Model):
    pass

class Show(models.Model):
    # this means you can have same show on different channels
    channels = models.ManyToManyField(Channel, related_name='shows')

class Episode(models.Model):
    # this means that one episode can be related only to one show
    show = models.ForeignKey(Show, related_name='episodes')

Channel.objects.filter(shows__name='Arrested Development')
Channel.objects.get(name='Discovery').shows.all()
Show.objects.get(name='Arrested Development').episodes.all()
#2 db queries, 1 join
Episode.objects.get(name='Arrested Development S01E01',
                    select_related='show').show.channels.all() 
#1 db query, 3 joins
Channel.objects.filter(shows__episode__name='Arrested Development S01E01')

and so on...

Upvotes: 1

almostflan
almostflan

Reputation: 640

Your initial stab at it looks fine. That is, you could use

class TVShow(models.Model)  
     channel = models.CharField()  
     show_name = models.CharField()  
     season = models.CharField()  
     episode = models.CharField()

And then you could just use the django orm to do the queries you were looking for.

That is, if you wanted all the channels with no duplicates, you would say

TVShow.objects.distinct('channel')

Django documentation for distinct().

As far as performance goes, this is the way to do it because you are effectively having the database do it. Databases are designed for these purposes and should be significantly faster than trying to trim it in code.

Upvotes: 2

Related Questions