Django ORM - 使用外键select_related和order_by

时间:2009-10-23 07:37:00

标签: django foreign-keys sql-order-by django-select-related

我有一个简单的音乐模式:艺术家,发行,曲目和歌曲。前三个都是逻辑结构,而第四个(Song)是(Artist,Release,Track)的特定实例,如mp3,wav,ogg等等。

我无法在数据库中生成有序的歌曲列表。问题是TrackRelease都有Artist。虽然Song.Track.Artist始终是表演者名称,但Song.Track.Release.Artist可以是表演者名称,也可以是“各种艺术家”进行编辑。我希望能够按其中一种排序,我无法找出使其正常工作的正确方法。

这是我的架构:

class Artist(models.Model):
    name = models.CharField(max_length=512)

class Release(models.Model):
    name = models.CharField(max_length=512)
    artist = models.ForeignKey(Artist)

class Track(models.Model):
    name = models.CharField(max_length=512)
    track_number = models.IntegerField('Position of the track on its release')
    length = models.IntegerField('Length of the song in seconds')
    artist = models.ForeignKey(Artist)
    release = models.ForeignKey(Release)

class Song(models.Model):
    bitrate = models.IntegerField('Bitrate of the song in kbps')
    location = models.CharField('Permanent storage location of the file', max_length=1024)
    owner = models.ForeignKey(User)
    track = models.ForeignKey(Track)

我的查询应该相当简单;过滤特定用户拥有的所有歌曲,然后按Song.Track.Artist.nameSong.Track.Release.Artist.name对其进行排序。这是我在视图中的代码,它按Song.Track.Artist.name排序:

songs = Song.objects.filter(owner=request.user).select_related('track__artist', 'track__release', 'track__release__artist').order_by('player_artist.name')

除非我使用order_by,否则无法让tblname.colname工作。我查看了基础查询对象的as_sql方法,该方法指示当内部联接获取Song.Track.Release.Artist时,临时名称T6用于Artist表因为内部联接已在同一个表上完成以获得Song.Track.Artist

>>> songs = Song.objects.filter(owner=request.user).select_related('track__artist', 'track__release', 'track__release__artist').order_by('T6.name')
>>> print songs.query.as_sql()
('SELECT "player_song"."id", "player_song"."bitrate", "player_song"."location", 
  "player_song"."owner_id", "player_song"."track_id", "player_track"."id", 
  "player_track"."name", "player_track"."track_number", "player_track"."length", 
  "player_track"."artist_id", "player_track"."release_id", "player_artist"."id", 
  "player_artist"."name", "player_release"."id", "player_release"."name", 
  "player_release"."artist_id", T6."id", T6."name" FROM "player_song" INNER JOIN 
  "player_track" ON ("player_song"."track_id" = "player_track"."id") INNER JOIN 
  "player_artist" ON ("player_track"."artist_id" = "player_artist"."id") INNER JOIN 
  "player_release" ON ("player_track"."release_id" = "player_release"."id") INNER JOIN 
  "player_artist" T6 ON ("player_release"."artist_id" = T6."id") WHERE 
  "player_song"."owner_id" = %s  ORDER BY T6.name ASC', (1,))

当我把它作为order_by中的表名时,它确实有用(参见上面的示例输出),但这似乎完全不可移植。当然有更好的方法来做到这一点!我错过了什么?

1 个答案:

答案 0 :(得分:26)

恐怕我真的无法理解你的问题是什么。

一些更正:select_related与排序无关(它根本不会更改查询集,只需跟随连接来获取相关对象并缓存它们);并且通过相关模型中的字段进行排序,您使用双下划线表示法,而不是点缀。例如:

Song.objects.filter(owner=request.user).order_by('track__artist__name')

但在您的示例中,您使用'player_artist',它似乎不是模型中任何位置的字段。我不明白你对可移植性的提及。