DjangoでSpotify APIを叩いてみる。

#はじめに

この記事はDjango Advent Calendar 2019の記事です。
対象読者はこれからDjangoを初めて見ようと言う層向けです。

前回の記事は@yuu-eguciさんの500エラーに関する内容でした。
https://qiita.com/yuu-eguci/items/a1e4b0a2f238d5ccc985

今回の記事はDjangoでSpotifyのAPIを実行してみようといった内容です。

# 事前準備

Spotifyのユーザーアカウントを作成する必要があるのですが、以下のクラスメソッドさんの記事が大変参考になります。
https://dev.classmethod.jp/etc/about-using-of-spotify-api/

記事のサンプルコードを実行したい方は、以下からチャートデータをCSV形式でダウンロードしてください。
https://spotifycharts.com/regional/jp/daily/latest

# サーバー側の実装

行儀が大変悪いですが、手軽に動作を確認してほしいのでviews.pyの中で全て纏めています。
違和感を与えてしまったら申し訳ありません。。。

```python

class SpotifySong:
    def __init__(self, song_name, uri):
        self.song_name = song_name
        self.uri = uri

def spotify(request) :
    # SpotifyのClientID,Secretを使って認可を実施
    client_id = ''
    client_secret = ''
    client_credentials_manager = spotipy.oauth2.SpotifyClientCredentials(client_id, client_secret)
    # Spotifyインスタンスを作成
    spotify = spotipy.Spotify(client_credentials_manager=client_credentials_manager)

    # SpotifyからダウンロードしたCSVファイルを読み込む
    songs = pd.read_csv(BASE_DIR + '/regional-jp-daily-latest.csv', index_col=0, header=1)

    # Spotifyから曲情報を取得
    spotify_songs_list = []
    for url in songs['URL']:
        spotify_songs_list.extend(spotify.audio_features(url))

    # 曲名をくっ付ける
    response_list = []
    for i,spotify_song in enumerate(spotify_songs_list):
        response_list.append(SpotifySong(songs.iat[i,0],spotify_song['uri']))

    # テンプレートを指定
    template = loader.get_template('spotify/spotify_base.html')
    context = {
        'response_list': response_list,
    }
    return HttpResponse(template.render(context, request))
```

spotify.audio_featuresで返ってくるレスポンスは以下を参考にしてください。
演奏時間、キーはもちろんその曲がどれだけアコースティックなのか・どれだけ踊れるかといった指標も返ってきます。今回の記事では省きますが、季節によって好まれる曲の傾向を学習するサービスとか作れそうですね!!
https://developer.spotify.com/documentation/web-api/reference/tracks/get-audio-features/

# クライアント側の実装

```django

{% if response_list %}
    <h1>デイリーランキング</h1>
    <ul>
    {% for response in response_list %}
    <li><a href="https://embed.spotify.com/?uri={{ response.uri }}"> {{response.song_name}} </a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>Spotifyからの楽曲取得に失敗しました。</p>
{% endif %}
```

簡素なHTMLですが、以下の様な感じでデイリーランキングが作れます。
クリックしたらSpotifyの曲ページに飛べるシンプルな画面ですが、初学者にとっては作れたら結構嬉しいのではないでしょうか？

<img width="338" alt="スクリーンショット 2019-12-01 19.09.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36448/ed478394-af69-9431-6d71-01ea12f05502.png">

## サンプルコードを理解する上で知っておきたいこと

DjangoでTemplateを扱う際、いくつか注意する事があります。
マニュアルはこちら。
https://docs.djangoproject.com/en/2.2/ref/templates/language/#templates

1.コレクションのサイズを取得したい時

{{ 変数|length }}という書き方で取得する必要があります。変数.lengthといった書き方は出来ません。

<img width="635" alt="スクリーンショット 2019-12-01 19.18.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36448/3d85cd51-ad87-0a3e-ad01-0a2cf17d7280.png">

2.コレクションのインデックスを指定して取得したい時

{{変数.0}}といった様に、直接.インデックス番号を指定するという方法でしか取得出来ません。
{{変数[[0]]}}という書き方は出来ません。

<img width="572" alt="スクリーンショット 2019-12-01 19.19.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36448/58948193-ef2c-82be-62ed-92a2c81b686a.png">

上記理由から、今回のサンプルコードは曲名を取得するために独自クラスを定義しています。
SpotifyAPIの戻り値と、CSV読み込みの結果を2つ渡す案も考えられますが、インデックス番号を用いた取得が困難なため、オブジェクトが別れて状態でデータを取り扱うのが面倒になります。

# おまけのトラブルシューティング

以下コマンドを打つと、Portが使われていますエラーが起きる場合があります。

```
python3 manage.py runserver

Django version 2.2.7, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Error: That port is already in use.
```

上記を解決するためには、以下手順でプロセスをkillする方法が一番簡単です。

1.ポートを調べる

```
lsof -i -P | grep 8000
Python    71504 user    4u  IPv4 0x2cdb3e922e88888      0t0  TCP localhost:8000 (LISTEN)
```

2.PIDを指定してkillコマンドを実行

```
kill -9 71504
```

# 終わりに

Django 3.0のfinalリリースの日のハードルは超えられていませんが、誰かの参考になると幸いです。。。
明日の Django アドベント・カレンダーは @shimayu22 さんです。よろしくお願いします!!