PF開発進んでいます。
記事書くペースが遅いので、もうかなり進んでいるのですが、自分の復習も兼ねて情報発信していきます。
前回のフローチャート図より引用してきました。
本日は黄色で囲った所をやっていきます。
ちなみに前回までの実装は↓です
映画の詳細を見たい!キャストの詳細を見たい!
本日は映画ポスターをクリックすると
・映画の詳細
・キャストの詳細
・クルー
が見れるようにします。
これが映画の詳細です。
この映画おすすめです。何回見ても泣いちゃいます。
そしてキャストの詳細。
マ・ドンソク兄貴、昨日誕生日だったんですね。おめでとうございました。
映画の詳細の概要は日本語対応しているんですが、キャストのプロフィールは日本語対応していないんですよ。
自動で翻訳して出せないかなって思ったんですが、そういった機能はできなさそう...(あったら教えてください。。)
今回書いていくコード
・urls.py(お馴染み)
・views.py(お馴染み)
・detail.html(映画詳細のHTML)
・cast-detail.html(キャスト詳細のHTML)
urls.py
urls.pyはこんな感じ
urlpatterns = [
path('detail/<int:id>', views.DetailCinemaView.as_view(),name='detail'),
#映画詳細表示
path('detailcast/<int:id>', views.DetailCastView.as_view(),name='cast'),
#キャスト詳細表示
]
views.py
長いので分けて書きます。
SEARCH_URL2 = 'https://api.themoviedb.org/3/movie/{movie_id}?api_key={my_api_key}&language=ja-JP&format=json'
SEARCH_URL3 = 'https://api.themoviedb.org/3/movie/{movie_id}/credits?api_key={my_api_key}&language=ja-JP'
def get_api_data2(movie_id):
url = SEARCH_URL2.format(movie_id=movie_id)
api = requests.get(url).text
result = json.loads(api)
return result
def get_api_data3(movie_id):
url = SEARCH_URL3.format(movie_id=movie_id)
api = requests.get(url).text
result = json.loads(api)
cast_i = result["cast"]
return cast_i
def get_api_data4(movie_id):
url = SEARCH_URL3.format(movie_id=movie_id)
api = requests.get(url).text
result = json.loads(api)
crew_i = result["crew"]
return crew_i
TMDbのAPIを取得します。
詳細とキャスト、クルーのAPIをとってきますので
前回とは違うURLから取得してきます。
TMDbより使いたいAPIを探してきます。
映画詳細は↑
キャスト詳細は↑
それぞれ載っていますので、それをコピーしてきてください。
ちなみにPOSTMANでURLを送信すると
このようになります。前回は['result']で区切られていましたが、今回はそのようなデータになっていないためコードが少し異なります。
キャストは前回と同じ形で、castのデータとcrewのデータを[]でとってきます↓
cast_i = result["cast"]
crew_i = result["crew"]
class DetailCinemaView(DetailView):
#映画の詳細を呼び出すview(cinema,cast,crewそれぞれをとってくる)
def get(self, request, *args, **kwargs):
movie_id = self.kwargs["id"]
items = get_api_data2(movie_id)
cast = get_api_data3(movie_id)
crew = get_api_data4(movie_id)
cinema_data = {
'title': items['title'],
'overview': items['overview'],
'image': items['poster_path'],
'release_date': items['release_date'],
'id': items['id']
}
cast_datalist = []
for i , item in enumerate(cast):
if i == 8: #8回繰り返します
break
cast_name = item['name']
cast_image = item['profile_path']
cast_character = item['character']
cast_id = item['id']
cast_data = {
'cast_name': cast_name,
'cast_image': cast_image,
'cast_character': cast_character,
'cast_id': cast_id,
}
cast_datalist.append(cast_data)
crew_datalist = []
for i , item in enumerate(crew):
if i == 8:
break
crew_name = item['name']
crew_image = item['profile_path']
crew_job = item['job']
crew_id = item['id']
crew_data = {
'crew_name': crew_name,
'crew_image': crew_image,
'crew_job': crew_job,
'crew_id': crew_id,
}
crew_datalist.append(crew_data)
return render(request, 'app/detail.html', {
'cinema_data': cinema_data,
'cast_datalist': cast_datalist,
'crew_datalist': crew_datalist
})
pythonの範囲ですが、enumerate関数はカウントアップです。
それぞれとってきた順番に番号をつけ、その順番が8になるまで繰り返し、8になったら終了させるようにしています。
キャストの顔写真は横スクロールも検討していますが、今回は取り急ぎの機能実装を心掛けてますので、このようにしております。
SEARCH_URL4 = 'https://api.themoviedb.org/3/person/{person_id}?api_key={my_api_key}&language=en-US'
#言語設定をja-JPにすると対応する言語がないので、空欄になってしまうため、en-USにしてあります。
SEARCH_URL5 = 'https://api.themoviedb.org/3/person/{person_id}/movie_credits?api_key={my_api_key}&language=ja-JP'
def get_api_data5(person_id):
url = SEARCH_URL4.format(person_id=person_id)
api = requests.get(url).text
result = json.loads(api)
return result
#キャスト詳細をとってきます。
def get_api_data6(person_id):
url = SEARCH_URL5.format(person_id=person_id)
api = requests.get(url).text
result = json.loads(api)
cast_film = result["cast"]
return cast_film
#出演している映画のデータをとってきます。
class DetailCastView(DetailView):
#キャスト詳細を呼び出すview
def get(self, request, *args, **kwargs):
person_id = self.kwargs["id"]
cast_detail = get_api_data5(person_id)
cast_detail_film = get_api_data6(person_id)
cast_detail_list ={
'name': cast_detail['name'],
'birthday': cast_detail['birthday'],
'image': cast_detail['profile_path'],
'biography':cast_detail['biography'],
}
cast_film_list = []
for i , item in enumerate(cast_detail_film):
if i == 8:
break
film_title = item['title']
relesedate = item['release_date']
image = item['poster_path']
cinema_id = item['id']
cast_detail_film_data ={
'film_title': film_title,
'releasedate': relesedate,
'image': image,
'cinema_id': cinema_id,
}
cast_film_list.append(cast_detail_film_data)
return render(request, 'app/cast-detail.html',{
'cast_detail_list': cast_detail_list,
'cast_film_list': cast_film_list
})
detail.html
{% extends 'app/base.html' %}
{% block content %}
<div class="my-5">
<div class="row">
<div class="col-md-6 text-center">
<img src="http://image.tmdb.org/t/p/w154{{ cinema_data.image }}" alt="画像です" class="img-fluid">
</div>
<div class="col-md-6">
<div class="card">
<div class="card-body px-2 py-1">
<div class="p-4">
<h3>{{ cinema_data.title }}</h3>
<form method="POST" action="{% url 'create' %}">
{% csrf_token %}
<input type="hidden" name="title" value="{{ cinema_data.title }}">
<input type="hidden" name="number" value="{{ cinema_data.id }}">
<input type="hidden" name="image" value="{{ cinema_data.image }}">
<button type="submit" class="btn btn-primary">登録する</button>
<button type="submit" class="btn btn-primary">レビューを見る</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="mb-5">
<h5>概要</h5>
<hr>
<p>{{ cinema_data.overview }}</p>
<p>公開日:{{ cinema_data.release_date }}</p>
</div>
<div class="cast-container">
{% for cast in cast_datalist %}
<div class="card" style="width: 8rem;">
<img class="card-img-top" src="https://image.tmdb.org/t/p/w154/{{ cast.cast_image }}" alt="card image cap">
<div class="card-body">
<h5 class="card-title">{{ cast.cast_character }}/{{ cast.cast_name }}</h5>
</div>
<a href="{% url 'cast' cast.cast_id %}" class="stretched-link"></a>
</div>
{% endfor %}
{% for crew in crew_datalist %}
<div class="card" style="width: 8rem;">
<img class="card-img-top" src="https://image.tmdb.org/t/p/w154/{{ crew.crew_image }}" alt="card image cap">
<div class="card-body">
<h5 class="card-title">{{ crew.crew_job }}/{{ crew.crew_name }}</h5>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
途中、「登録する」と「レビューを見る」のフォームを作っていますが、今回は説明しません。
DetailCinemaView(DetailView)でとってきたデータを
return render(request, 'app/detail.html', {
'cinema_data': cinema_data,
'cast_datalist': cast_datalist,
'crew_datalist': crew_datalist
})
のように返しておりますので、それぞれこのデータを{{}}と{% %}で使い表示させるようにします。
cast-detail.html
{% extends 'app/base.html' %}
{% block content %}
<div class="my-5">
<div class="row">
<div class="col-md-6 text-center">
<img src="http://image.tmdb.org/t/p/w154{{ cast_detail_list.image }}" alt="画像です" class="img-fluid">
</div>
<div class="col-md-6">
<div class="card">
<div class="card-body px-2 py-1">
<div class="p-4">
<h3>{{ cast_detail_list.name }}</h3>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="mb-5">
<h5>プロフィール</h5>
<hr>
<p>プロフィール:{{ cast_detail_list.biography }}</p>
<p>誕生日:{{ cast_detail_list.birthday }}</p>
</div>
<div class="cast-container">
{% for cast in cast_film_list %}
<div class="card" style="width: 8rem;">
<img class="card-img-top" src="https://image.tmdb.org/t/p/w154/{{ cast.image }}" alt="card image cap">
<div class="card-body">
<h5 class="card-title">{{ cast.film_title }}</h5>
<h5 class="card-title">{{ cast.releasedate }}</h5>
</div>
<a href="{% url 'detail' cast.cinema_id %}" class="stretched-link"></a>
</div>
{% endfor %}
</div>
{% endblock %}
キャストの方もほぼ同じです。
終わりに
上記コードを書けば、検索した映画の詳細、また出ているキャスト・クルーも見れて、尚且つキャストをクリックしたら、キャストの詳細も見れちゃうシステムです。
ここは正直必要ない機能かもしれませんが、データの扱い方を学ぶということで非常に勉強になりました。
POSTMANでデータを見るというもの大事ですし、書かれている内容を把握しJSON形式の文字列からjson.loads(api)で辞書型に直すということも学べました。
次はマイリストに登録するという機能をやっていこうと思います。