【Django】TMDbからAPIを取得し、映画を検索したい！

# 最近観た映画はアントマン&ワスプ クアントマニア

映画を見終わったら、皆さんどうしますか？
友達と喋る？とりあえずご飯？
それも良いですよね！

僕は見終わったらずっとその映画のことを考えてしまうんですよね、余韻というやつです。

前置きが長くなりましたが



## TMDbからAPIを取得して映画を検索したい！

ということをやりました。
PF制作と直結する機能を実装してみた！第一弾です。
検索しても、意外とちゃんと書かれていることがなさそうなので、書いてみました。
Djangoでの例もあまりなさげ...？需要あるかな？


## 完成形

検索画面
![スクリーンショット 2023-02-22 234430.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2854762/2f46cd0d-ca0a-7d6c-5247-a5ff30fe6f28.png)

検索結果表示

![スクリーンショット 2023-02-22 234554.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2854762/2deb9c63-3116-9b1a-616f-3c70eada4d4f.png)


取得するものは
・ポスター
・タイトル
・公開日
の3点です。

ちなみにHTML&CSSや一部pythonのコードは

https://www.youtube.com/watch?v=WvGQ8gmXZgM

こちらのyoutubeの動画を参考にしており
デザインはとりあえずです。



## 制作環境

・windows10
・Django
・VScode
・TMDb API

https://www.themoviedb.org/?language=ja


上記のデータベースを使います。
API取得するための登録方法はgoogle先生並びにchatGPT先生に聞いていただければ、解決すると思います。

またpythonのフレームワークDjangoを使って実装しますので


https://qiita.com/ri-tama/items/328446e5194f40877cf7

https://qiita.com/ri-tama/items/098668be4b941b49719d

上記記事でアプリの作成まで終わらせます。
前置きが長くなりましたが(2回目)制作に入ります。

# 今回書いていくコード

・urls.py(urlを入力したときに呼び出すviewを宣言するファイル)
・views.py(処理を書いていくファイル)
・forms.py(入力フォームの土台を作るファイル)
・index.html(検索画面のTOPページ)
・cinema.html(検索結果のページ)

上記ファイルです。()内はあくまで自分のイメージです。


# urls.pyの書き方


```django urls.py
from django.urls import path
from searchapp import views
from . import views

urlpatterns = [
    path('', views.IndexListView.as_view(),name='index'),
]

```
　
何も入っていない時にIndexListViewを呼び出します。要するにTOPページです。
　　
# forms.pyの書き方

```django forms.py
from django import forms

class SearchForm(forms.Form):
    title = forms.CharField(label='タイトル',max_length=200, required=True)

```
　　
入力フォームを作ります。
検索フォームなのでSearchFormと書いておきます。
'required = True'でフォームに対しての入力が必須となります。

　　
# views.pyの書き方 その1

  
```django views.py
from django.shortcuts import render
from django.views.generic import ListView
from .forms import SearchForm
import json
import requests

SEARCH_URL = 'https://api.themoviedb.org/3/search/movie?api_key={my_api_key}&language=ja-jp&page=1&include_adult=false&format=json'


```
　　
views.pyは長くなるので分割しました。
URLは下記サイトからとってきます。
目的に応じて使うURLが違うので、ご注意ください。

https://developers.themoviedb.org/3/getting-started/introduction

今回は映画の検索なので、タイトルを検索したら映画がヒットするものをとってきます。
下記画面の丸をつけたところから、URLをとってきます。

![スクリーンショット 2023-02-23 002623.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2854762/329538e9-e22b-da4f-66fe-02e3ceeff895.png)

　　
　　
<<api_key>>は自分のapi_keyを入力してください。

　　

# views.pyの書き方 その2
    

```django views.py

def get_api_data(params):
    api = requests.get(SEARCH_URL, params=params).text
    result = json.loads(api)
    items = result["results"]
    return items

```
　　
request.getでURLからAPIを取得します。
取得してきたオブジェクトの形式が、そのまま使うには困難な為.textとし、
文字列形式のデータとして扱えるようにします。

検索には、検索するタイトルの文字列が必要です。
なのでここではparams=paramsとして、タイトルを代入するようにしています。

get_api_data関数内の1行目でapiをJSONの文字列で取得
2行目のjson.loads()で()内の文字列を辞書型に変換
3行目でresultの中身であるresultsに対応するデータをitemsに納めて、データを返します。

対応するデータについて補足です。

https://www.postman.com/

上記サイトでは取得したいAPIの中身を見ることができます。
アントマンを検索すると以下の画面(一部抜粋)のようになります。


![スクリーンショット 2023-02-23 102204.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2854762/db40c8b9-3159-4348-f513-c67ec07b2a1b.png)


なので今後使いたいAPIの中身がわからないということがあれば
このPOSTMANを使うと良いでしょう。　

# views.pyの書き方 その3
　　
```django views.py

class IndexListView(ListView):
    def get(self, request, *args, **kwargs):
        form = SearchForm(request.POST or None)

        return render(request, 'app/index.html', {
            'form': form,
        })

    def post(self, request, *args, **kwargs):
        form = SearchForm(request.POST or None)

        if form.is_valid():
            query = form.cleaned_data['title']
            params = {
                'query': query,
                'hits': 28,
            }


```

ここでは2つの関数を書いています。
1つ目がget関数。GETメソッドに要求があったときに呼び出される関数です。
検索formが出る(描画される)のはこの関数がある為ですね。

2つ目がpost関数。
if～の部分は、formに入力された文字が正しければ
cleaned_data[]でタイトルを取得し、queryに代入しております。

その後paramsという変数に上記queryとhits:28(最大28件まで検索結果を出してもらう)
を代入します。
```django views.py

items=get_api_data(params)

```
　　
paramsを引数とし、get_api_data関数で検索をします。
その結果がitemsに格納されます。
　　
# views.pyの書き方 その4

```django views.py

            cinema_data = []
            for i in items:
                title = i['title']
                image = i['poster_path']
                release_date = i['release_date']
                id = i['id']
                cinema = {
                    'title': title,
                    'image': image,
                    'release_date': release_date,
                    'id': id
                }
                cinema_data.append(cinema)

```

cinema_data=[]という空のリストを作成。
取得してきたデータをiに入れて
・title
・poster_path(ポスター)
・release_date(公開日)
・id
中身からそれぞれのデータを変数に代入。

変数を辞書型に変換しcinemaへ格納します。
cinemaを.appendでcinema_dataへ追加します。

# views.pyの書き方 その5

　
```django viewa.py
            return render(request, 'app/cinema.html', {
                'cinema_data': cinema_data,
                'keyword': query,
            })

        return render(request, 'app/index.html', {
            'form': form
        })
```

最後に辞書型のデータ(cinema_data)とタイトル(query)をcinema.htmlへ持っていきましょう。


# HTMLの書き方

HTMLについてはあまり触れません。
bootstrapを使い装飾を施し、base.htmlを書いてヘッダー・フッター部分は共通にしてあります。

```HTML
{% extends 'app/base.html' %}
{% load widget_tweaks %}

{% block content %}

<div class="text-center my-5">
    <form method="post">
        {% csrf_token %}
        <div class="align-items-center">
            {% render_field form.title class="form-control" placeholder="キーワードから探す" %}
            <button class="btn btn-primary mt-2" type="submit">検索</button>
        </div>
    </form>
</div>


{% endblock %}


```
　　
TOPページですね。
検索窓があるページです。
{% csrf_token %}はお忘れなく。


```HTML
{% extends 'app/base.html' %}

{% block content %}
<div class="text-center my-5">
    <div class="mb-5">
        <h3>「{{ keyword }}」の検索結果</h3>
    </div>
    <div class="row">
        {% for cinema in cinema_data %}
            <div class="col-3 mb-3">
                <div class="card img -thumbnail cinemalist h-100">
                    <img src="http://image.tmdb.org/t/p/w154{{ cinema.image }}" alt="画像です" class="card-img-top card-thum">
                    <div class="card-body text-center px-2 py-3">
                        <h5 class="font-weight-bold">{{ cinema.title }}</h5>
                        <h5 class="font-weight-bold">{{ cinema.release_date }}</h5>
                    </div>
                    <a href="{% url 'detail' cinema.id %}" class="stretched-link"></a>
                
                </div>
            </div>
        {% empty %}
          <p>該当するものはありません。</p>
        {% endfor %}
    </div>
</div>

{% endblock %}
```


・{{  }}はデータをとってくるもの
・{%  %}はデータに何らかの処理を加えるもの
です。
{{ keyword }}は検索した文字が入り
{% for cinema in cinema_data %}はcinema_dataをcinemaにfor文で繰り返し代入します。

{{ cinema.image }}
{{ cinema.title }}
{{ cinema.release_date }}

それぞれ自動で入力されていきます。

ちなみに
```HTML
<a href="{% url 'detail' cinema.id %}" class="stretched-link"></a>
```
こちらは次に詳細画面へと遷移する時のリンクです。次回の記事で作っていきます。


# 完成

あとはサーバーを立ち上げて確認すると、検索できるようになっています。

書いている途中、ここってどういう意味だっけ・・・
となったりしてChatGPT先生に聞きながら書き上げたので
インプットもアウトプットもできた感じがあります。

引っかかった部分もあったりしたので
それは別記事で投稿しようかなと思います。

### 読んでいただきありがとうございました！！！