2009-10-23 28 views
5

Basit bir müzik şem var: Artist, Release, Track ve Song. İlk 3, tüm mantıksal yapılardır, dördüncü ise (Song) bir mp3, wav, ogg, neyse, bir (Artist, Release, Track) özel bir örneğidir.Django ORM - select_lated ve order_by yabancı tuşlarla

Veritabanındaki Şarkılar'ın sıralı bir listesini oluşturmakta sorun yaşıyorum. Yakalama, hem Track hem de Release'un bir Artist'a sahip olmasıdır. Song.Track.Artist her zaman performansın adıdır, Song.Track.Release.Artist derlemeler için bir performans adı veya "Çeşitli Sanatçılar" olabilir. Birini diğerine göre sıralamak istiyorum ve bu işi yapmak için doğru yolu anlayamıyorum.

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) 

Benim sorgu oldukça basit olmalıdır;: Burada

benim şema var Belirli bir kullanıcıya ait tüm şarkıları filtreleyin ve ardından bunları Song.Track.Artist.name veya Song.Track.Release.Artist.name ile sıralayın.

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

ben tblname.colname kullanmadıkça çalışmaya order_by alınamıyor: İşte Song.Track.Artist.name göre sıralama edilen bir görünümü içinde benim kod. Bir iç birleştirme zaten Song.Track.Artist:

almak için aynı tablo üzerinde yapılan bu yana Song.Track.Release.Artist için geçici adı T6 için T6 geçici adı almak için yapıldığını gösterir, temel sorgu nesnesinin as_sql yöntemine bir göz attım
>>> 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,)) 

Bunu tablo adında order_by olarak yazdığımda işe yarar (yukarıdaki örnek çıktıya bakın), ancak bu tamamen taşınabilir değil gibi görünüyor. Elbette bunu yapmak için daha iyi bir yol var! Neyi kaçırıyorum?

cevap

24

Korkarım ki sorunun ne olduğunu gerçekten anlayamıyorum.

Birkaç düzeltme: select_related'un sipariş ile ilgisi yoktur (ilgili nesneleri almak ve onları önbelleğe almak için yalnızca bir araya getirme işlemlerini takip eder; ve ilişkili bir modeldeki bir alan tarafından sipariş vermek için, noktalı olmayan çift alt çizgi notasyonu kullanın. Örneğin:

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

Ama örnekte, her yerde modelinde bir alan olarak görünmüyor 'player_artist' kullanın. Ve ben taşınabilirlik referansını anlamıyorum.

İlgili konular