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…
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?
Create your profile
Only paid subscribers can comment on this post
Check your email
For your security, we need to re-authenticate you.
Click the link we sent to , or click here to sign in.