Personal tools
You are here: Home メンバー Moo's folder TurboGears TurboTunes
Document Actions

TurboTunes

by Moo.Blaze last modified 2006-04-10 21:59

TurboTunesチュートリアル

by Ronald Jaramillo

TurboGearsでApple社から市場シェアを盗みましょう

これはKevin Dangoorによる "TurboTunes"動画(19.3MB QuickTime) のテキストバージョンです。動画は Internet ArchiveBitTorrent経由 でも入手可能です。

このチュートリアルではあなた専用のミュージックストアを TurboGears を使って実装する方法をご覧いただけます。 私たちが達成するために何を計画するのかを理解するには この短いクリップ をご覧ください。

img/turbotunes.png

私たちは以下のステップをカバーします:

新規プロジェクトの作成

tg-admin quickstart を使用して新しいTurboGearsプロジェクトの作成を開始します。 プロジェクトは TurboTunes と呼ぶことにします。

tg-admin quickstart

データベースの構成

プロジェクトのデータベースを作成し、dev.cfg と prd.cfg をあなたのデータベース設定に合わせて構成します。 私は postgres を使用しているのでこのようになりそうです。

[global]

# DATABASE

# pick the form for your database
sqlobject.dburi="postgres://postgres@localhost/turboTunes"

モデルの定義

モデルファイル(model.py)を開き、モデルクラスの定義を開始します。 アーティストをジャンルでグループ分けしたいので:

class Genre(SQLObject):
  name = StringCol(length=200)
  artists = RelatedJoin('Artist')

このようなアーティストオブジェクトで多対多のリレーションを定義します。

class Artist(SQLObject):
  name = StringCol(length=200)
  genres = RelatedJoin('Genre')
  albums = MultipleJoin('Album')

アーティストは(複数の)アルバムを作るので、新たにオブジェクトを定義します。

class Album(SQLObject):
  name = StringCol(length=200)
  artist = ForeignKey('Artist')
  songs = MultipleJoin('Song')

そして、最後は楽曲です。

class Song(SQLObject):
  name = StringCol(length=200)
  album = ForeignKey('Album')

tg-admin sql create を実行するとテーブルが作成されるでしょう。

tg-admin sql create

そのまま続けたい、あるいはタイピングする気分でない場合には ここから モデルファイルをダウンロードしてください。

CatWalkをマウント

controllers.py ファイルを開き、次のようにしてCatWalkをマウントします:

import turbogears
from turbogears import controllers
from turbogears.toolbox.catwalk import CatWalk
import model

class Root(controllers.Root):
    catwalk = CatWalk(model)

    @turbogears.expose()
    def index(self):
        return dict()

モデルをインポートすることと、それをパラメータとしてCatWalkに渡すことを忘れないでください。

Webサーバを起動します。

python turboTunes-start.py

CatWalkが http://localhost:8080/catwalk で開始するでしょう。

ストアを生成

CatWalkを使用することで、あなたのストアをすばやく生成することができます。ジャンルの追加から開始して、アーティストを何人か追加します。 アーティストがどのジャンルに属するかを構成します。アルバムをアーティストに追加して、楽曲をアルバムに追加して… いくつかやると このクリップ のようになるでしょう。

img/catwalk_clip.png

コントローラの編集

コントローラを次のメソッドで実装します。

  • index

    メインのHTMLテンプレートを提供します。

  • genres

    ジャンルのリストを構築し、返します。

  • artists

    リクエストされたジャンルに属するアーティストのリストを構築し、返します。

  • albums

    リクエストされたアーティストに属するアルバムのリストを構築し、返します。

  • songs

    リクエストされたアルバムに属する楽曲のリストを構築し、返します。

import turbogears
from turbogears import controllers
from turbogears.catwalk import CatWalk
import model

class Root(controllers.Root):
    catwalk = CatWalk(model)

    @turbogears.expose()
    def songs(self,album):
      a = model.Album.get(album)
      return dict(rows= [[song.name,
                          song.album.artist.name,
                          song.album.name]
                          for song in a.songs])

    @turbogears.expose()
    def albums(self,artist):
      a = model.Artist.get(artist)
      return dict(selectID='albums',
                  options=[{'label':album.name,
                            'value':album.id}
                            for album in a.albums])

    @turbogears.expose()
    def artists(self,genre):
      g = model.Genre.get(genre)
      return dict(selectID='artists',
                  options=[{'label':artist.name,
                            'value':artist.id}
                          for artist in g.artists])

    @turbogears.expose()
    def genres(self):
      return dict(selectID='genres',
                  options=[{'label':genre.name,
                            'value':genre.id}
                           for genre in model.Genre.select()])

    @turbogears.expose(html="TurboTunes.templates.tunes")
    def index(self):
        return dict()

まだタイピングする気分ではありませんか? ここの コントローラファイルをダウンロードしてください。

テンプレートの編集

TurboTunes ミュージックストアは3つのセレクトボックスとグリッドビューで構成されます。 最初のボックスにはジャンルが一覧され、2番目はアーティスト、3番目はアルバムとなります。 グリッドビューには楽曲が表示されます。

img/turbotunes.png

テンプレート(templates/tunes.kid)には(CatWalkユーザがインターフェイスをレンダリングするために)MochiKitとWidgetsをインポートすべきです。 細かな機能をすべて引き出すには、いくつかの関数を書く必要があります。

  • init

    bodyのonload関数から呼ばれるべきものです。 ジャンルのリストをロードして、グリッドを初期化します。

  • retrieveGenres

    genresメソッドへのAjaxメソッドです。 loadListへのコールバックをセットします。

  • loadList

    JSONデータ構造をセレクトボックスを生成するWidget.select.loadに渡します。

  • retrieveArtistForGenre

    artistsメソッドへのAjaxリクエストで、選択されたジャンルをパラメータとして渡します。

  • retrieveAlbumsForArtist

    albumsメソッドへのAjaxリクエストで、選択されたアーティストをパラメータとして渡します。

  • retrieveSongsForAlbum

    songsメソッドへのAjaxリクエストで、選択されたアルバムをパラメータとして渡します。

  • loadTable

    Widget.grid.renderを呼び出し、JSONデータ構造を渡します。

これは最も大きいプロジェクトファイルです:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" >

<head>
    <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
    <title>TurboTunes</title>
    <link rel="stylesheet" type="text/css" href="/tg_static/css/widget.css" />
    <script src="/tg_static/js/widget.js"></script>
    <script src="/tg_js/MochiKit.js"></script>
    <style>
      body,td { font-family:verdana,sans-serif; }
      #top
      {
        background-image:url('static/images/topbg.png');
        background-repeat:repeat-x;
        height:70px;
        font-size:10px;
        color:#666;
        font-weight:900;
      }
      select {width:255px;padding:0;margin:0}
      .list_head {
            height:17px;
            font-size:10px;
            color:#666;
            font-weight:900;
            text-align:center;
            border-right:1px solid #666;
            background-image:url('static/images/bg.png');
            background-repeat:repeat-x;
          }
      .grid td {height:13px;font-size:10px;}
      #app {border:1px solid #666 }
    </style>
    <script>
      <![CDATA[
      function loadTable(content)
      {
        var MIN_ROWS = 10;
        content['headers'] =['Name','Artist','Album'];
        var n = content.rows.length;
        if( n < MIN_ROWS)
        {
          for(var i=0;i< (MIN_ROWS-n);i++)
          {
            content.rows[content.rows.length]=[' ',' ',' '];
          }
        }
        replaceChildNodes('song_placeholder',Widget.grid.render('songs',content));
      }
      function loadList(result)
      {
        Widget.select.load(result['selectID'],result);
      }
      function retrieveGenres()
      {
        var e = loadJSONDoc('genres');
        e.addCallback(loadList);
      }
      function retrieveArtistForGenre(list)
      {
        var id= list.options[list.selectedIndex].value;
        var e = loadJSONDoc('artists?genre='+ id);
        e.addCallback(loadList);

        Widget.select.load('albums',{options:[]}); //clear the albums
        loadTable({rows:[]}); //clear the songs
      }
      function retrieveAlbumsForArtist(list)
      {
        var id= list.options[list.selectedIndex].value;
        var e = loadJSONDoc('albums?artist='+ id);
        e.addCallback(loadList);

        loadTable({rows:[]}); //clear the songs
      }
      function retrieveSongsForAlbum(list)
      {
        var id= list.options[list.selectedIndex].value;
        var e = loadJSONDoc('songs?album='+ id);
        e.addCallback(loadTable);
      }
      function init()
      {
        loadTable({rows:[]});
        retrieveGenres();
      }
      ]]>]]&gt;<![CDATA[
    </script>
</head>
<body onload="init()">
<table width="100%" cellpadding="0" cellspacing="0" border="0">
  <tr>
    <td align="center">

      <table id="app" cellpadding="0" cellspacing="0" border="0">
        <tr>
          <td colspan="3" id="top" align="center">
              TurboTunes
              <br />
              <img src="static/images/tg.png" />
          </td>
        </tr>
        <tr>
          <td class="list_head">Genre</td>
          <td class="list_head">Artist</td>
          <td class="list_head">Albums</td>
        </tr>
        <tr>
          <td valign="top"><select name="genres" id="genres"
                            onchange="retrieveArtistForGenre(this)"
                            size="15"></select></td>
          <td valign="top"><select name="artists" id="artists"
                            onchange="retrieveAlbumsForArtist(this)"
                            size="15"></select></td>
          <td valign="top"><select name="albums" id="albums"
                            onchange="retrieveSongsForAlbum(this)"
                            size="15"></select></td>
       </tr>
       <tr>
          <td colspan="3">
            <div id="song_placeholder"></div>
          </td>
        </tr>
      </table>

    </td>
  </tr>
</table>
</body>
</html>

ここで 取得してください。

要約

これでおしまいです! あなたは黒いタートルネックの服を着て、狂信者たちに"もうひとつのもの"を見せる準備ができています。

もちろん楽曲を買い、小さいサンプルを聴き、アルバムのアートワークを見られるようになるべきですが、それは宿題として残っています。

Zip圧縮されたプロジェクトファイルは こちらから どうぞ。


Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: