Robert Rambles

Share this post
Make your Django Query Logic DRYer
blog.robertroskam.com

Make your Django Query Logic DRYer

Let’s say you’re making a database of music. It’s going to include Albums and Singles and Artists. Multiple artists could have participated…

Robert Roskam
Apr 30, 2016
Share this post
Make your Django Query Logic DRYer
blog.robertroskam.com

Let’s say you’re making a database of music. It’s going to include Albums and Singles and Artists. Multiple artists could have participated on the same Song. Here’s a relatively simple data relationship:

from django.db import models
class Artist(models.Model):    first_name = models.CharField(max_length=50)    last_name = models.CharField(max_length=50)
class Album(models.Model):    name = models.CharField(max_length=50)    release_date = models.DateField()
class Song(models.Model):    artists = models.ManyToManyField(Artist)    albums = models.ManyToManyField(Album)    name = models.CharField(max_length=100)    release_date = models.DateField()

You’ll note it’s a pain in the butt to find out who sang a song. Let’s say you want to find the list of Artists in the Lion King. Your query may look something like this:

songs = Song.objects.filter(albums__name='Lion King') artists_from_lion_king = Artist.objects.filter(song_set__in=songs)

Admittedly, this is really bad logic, since it’s only useful for the Lion King. But it’s totally possible you might find yourself doing something like that in a view, where you’re passing in the name as parameter. But that’s dumb. Don’t do that bit code right above. Do this instead:

from django.db import models
class Artist(models.Model):    first_name = models.CharField(max_length=50)    last_name = models.CharField(max_length=50)
    @property    def albums(self):        songs = self.song_set.all()        return Album.objects.filter(song_set__in=songs)
class Album(models.Model):    name = models.CharField(max_length=50)    release_date = models.DateField()
    @property    def artists(self):        songs = self.song_set.all()        return Artist.objects.filter(song_set__in=songs)
class Song(models.Model):    artists = models.ManyToManyField(Artist)    albums = models.ManyToManyField(Album)    name = models.CharField(max_length=100)    release_date = models.DateField()

A little explanation as to the magic going on. You’re collecting the song_set related to each model, Album and Arists, and having a generalized function run to collect for you a queryset (note not a list, which makes this doubly awesome).

I do this pattern all the time. It’s extremely convenient.

However, I’m sure there are other options out there. How do you all keep your query logic in Django DRY?

Share this post
Make your Django Query Logic DRYer
blog.robertroskam.com
Comments

Create your profile

0 subscriptions will be displayed on your profile (edit)

Skip for now

Only paid subscribers can comment on this post

Already a paid subscriber? Sign in

Check your email

For your security, we need to re-authenticate you.

Click the link we sent to , or click here to sign in.

TopNew

No posts

Ready for more?

© 2022 Robert Roskam
Privacy ∙ Terms ∙ Collection notice
Publish on Substack Get the app
Substack is the home for great writing