How to properly order by ManyToMany's through table?

I have to following models:

class Song(models.Model):
    (...)
    
class Playlist(models.Model):
    (...)
    songs = models.ManyToManyField(
        Song,
        through="PlaylistSong",
        through_fields=("playlist", "song"),
    )


class PlaylistSong(models.Model):
    playlist = models.ForeignKey(Playlist, on_delete=models.CASCADE)
    song = models.ForeignKey(Song, on_delete=models.CASCADE)
    (...)
    order = models.IntegerField(default=0)

When the user selects an Playlist I want to return the songs from that playlist, but I can’t order the songs because the order field is in the Album, not Playlist:

playlist = Playlist.objects.get(id=pk).songs.order_by("order")

This make sense, but what I can’t figure out is, given I have the playlist and therefore the objects of PlaylistSong, how can I order them by the field PlaylistSong.order?

I have found a way, which is:

playlist = Playlist.objects.get(id=pk)
playlist_songs = PlaylistSongs.objects.filter(playlist=playlist).order_by("order")

But this won’t return songs I would have to iterate another time the object playlist_songs to then find the songs:

playlist = Playlist.objects.get(id=pk)
playlist_songs = PlaylistSongs.objects.filter(playlist=playlist).order_by("order")
songs = [playlist_songs.song for playlist_song in playlist_songs ]

Is there a way to avoid that much iteration when using order_by in ManyToManyFields?

I think you can do it like this:

playlist = Playlist.objects.get(id=pk)
songs = Song.objects.filter(playlistsong__playlist=playlist).order_by("playlistsong__order")
1 Like

Thank you very much for your reply. I forgot to reply, but this looks like a viable option.

At the end I used python’s sorted to order the list, like this:

ordered_list = sorted(songs,  key=attrgetter("order"))