2009-10-23 86 views
5

我有一個簡單的音樂模式:Artist,Release,Track和Song。前三個都是邏輯構造,而第四個(歌曲)是一個(藝術家,發佈,音軌)的特定實例,如mp3,wav,ogg等等。Django ORM - select_related和order_by外鍵

我在生成數據庫中歌曲的有序列表時遇到了問題。值得注意的是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中的表名時,它確實有效(請參閱上面的示例輸出),但這看起來完全不可移植。當然有更好的方法來做到這一點!我錯過了什麼?

回答

24

恐怕我真的不明白你的問題是什麼。

幾個更正:select_related與排序無關(它根本不會更改查詢集,只是跟隨連接以獲取相關對象並緩存它們);並按照相關模型中的字段排序,使用雙下劃線符號,而不是虛線。例如:

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

但在你的榜樣,你用「player_artist」,這似乎並沒有在模型的任意位置的字段。我不明白你提到可移植性。