序章

この記事では、さまざまな都市の現在の天気を表示するDjangoアプリを作成します。

Weather App Home Page with London, Tokyo, Las Vegas, and Miami weather

現在の気象データは、 Open Weather MapAPIによって提供されます。

データベースを操作してフォームを作成します。 このチュートリアルで学んだことは、後でより複雑なプロジェクトに適用できます。

前提条件

  • このプロジェクトにはPythonがインストールされている必要があります。詳細については、このチュートリアルシリーズを参照できるはずです。

この記事のコードはPython3とDjango3.0で記述されているため、このチュートリアルに従うには、両方にある程度精通している必要があります。

ステップ1—プロジェクトの設定

Djangoのインストールは、他のPythonライブラリのインストールと似ています。

  • 仮想環境を開始し、pipを実行してDjangoをインストールできます。
  • または、プロジェクトディレクトリを作成し、pipenvを実行してから、pipenvシェルをアクティブ化することもできます。

どちらの方法でも機能しますが、この記事ではpipenvを使用します。

注:別のDjangoインストール方法については、このチュートリアルシリーズを参照して追加情報を入手できるはずです。

公式ドキュメントには、HomebrewまたはLinuxbrewを使用してpipenvをインストールする手順が記載されています。 pipと一緒にpipenvをインストールすることも可能です。

ターミナルで、環境ディレクトリを作成します。

  1. mkdir the_weather_env

次に、環境ディレクトリに移動します。

  1. cd the_weather_env

次に、pipenvを使用してDjangoをインストールします。

  1. pipenv install django

これにより、最新バージョンのDjangoがインストールされます。 この記事を書いている時点では、Djangoはバージョン3.0.5です。

この瞬間に、pipenvを使用して、後で使用するRequestsライブラリをインストールします。

  1. pipenv install requests

ターミナルで次のコマンドを実行して、プロジェクトのvirtualenvをアクティブにします。

  1. pipenv shell

これにより、新しいシェルサブプロセスが生成されます。

ステップ2—Djangoプロジェクトを開始する

Djangoをインストールしたら、まだ作成していない場合は、このプロジェクトのディレクトリを作成して移動します。

Djangoがプロジェクトを生成するために提供するstartprojectコマンドを実行できます。

  1. django-admin startproject the_weather

Djangoはあなたのディレクトリにいくつかの新しいファイルを作成しているはずです。

開発サーバーを起動してみましょう。 これを行うには、ターミナルの新しいディレクトリに移動します。

  1. cd the_weather

次に、manage.pyを使用して、ターミナルでrunserverコマンドを実行します。

  1. python manage.py runserver

ターミナルを確認すると、アプリのURLが表示されます。 デフォルトでは、127.0.0.1:8000になっているはずです。

Terminal window depicting development server up and running

次に、Webブラウザーを開き、そのURLにアクセスします。

Browser window depicting Django development server Congratulations page

「おめでとうございます」ページが表示された場合は、Djangoが正しく設定されていることがわかります。

ステップ3—管理ダッシュボードにログインする

次に、Djangoが提供する管理ダッシュボードにログインします。 これを実現するには、まずデータベースを移行する必要があります。つまり、Djangoはデフォルトのアプリに必要な事前定義されたテーブルを作成します。

まず、サーバーを停止する必要があります。 環境に応じて、これはキーボードコマンドCONTROL+CまたはCTRL+Cで実行できます。

次に、ターミナルでmigrateコマンドを実行します。

  1. python manage.py migrate

そのコマンドを実行することにより、Djangoは設定のデフォルトデータベースであるSQLiteデータベースを作成し、そのデータベースにいくつかのテーブルを追加しました。 プロジェクトディレクトリに新しいdb.sqlite3ファイルが表示されれば、データベースが作成されたかどうかがわかります。

Djangoが提供するテーブルの1つは、ユーザーテーブルです。これは、アプリ内のすべてのユーザーを格納するために使用されます。 作成しているアプリにはユーザーは必要ありませんが、管理者ユーザーがいると、管理ダッシュボードにアクセスできます。

管理者ユーザーを作成するには、ターミナルでcreatesuperuserコマンドを実行します。

  1. python manage.py createsuperuser

管理者ユーザーのユーザー名、電子メールアドレス、およびパスワードを入力して、指示に従います。 終了したら、ターミナルでサーバーを再起動する必要があります。

  1. python manage.py runserver

Webブラウザーで、127.0.0.1:8000/adminに移動して管理ダッシュボードにアクセスします。

このページに移動できるのは、urls.pyadminが設定されているためです。

作成したユーザー名とパスワードでログインすると、Django管理ダッシュボードが表示されます。

Browser window depicting Django Admin Dashboard

グループユーザーは、Djangoがアクセスできる2つのモデルを表しています。 モデルは、データベース内のテーブルの単なるコード表現です。 Djangoはさらに多くのテーブルを作成しましたが、残りのテーブルに直接アクセスする必要がないため、モデルは作成されませんでした。

[ユーザー]をクリックすると、ユーザーテーブルの詳細が表示され、作成したユーザーが表示されます。 ダッシュボードのさまざまなリンクをクリックして、何が利用できるかを確認してください。 ユーザーを削除しないように注意してください。削除しないと、createsuperuserを再度実行する必要があります。

とりあえず管理ダッシュボードを離れて、コードに取り組みましょう。 天気予報アプリ用にプロジェクト内にアプリを作成する必要があります。

ステップ4—アプリを作成する

Djangoでは、 apps を使用して、プロジェクトの機能を分離できます。 Djangoの場合、アプリはプロジェクトの特定の機能を指します。

たとえば、settings.pyファイルを見ると、INSTALLED_APPSリストが表示されます。

インストールされた最初のアプリ(django.contrib.admin)は、今使用したものです。 すべての管理機能を処理し、それ以外は処理しません。 プロジェクトのもう1つのアプリは、デフォルトでdjango.contrib.authです。これにより、管理ダッシュボードにログインできます。

あなたの場合、天気の表示に関連するすべてを処理する新しいアプリを作成する必要があります。

まず、サーバーを停止する必要があります。

次に、ターミナルでstartappコマンドを実行します。

  1. python manage.py startapp weather

startappを実行することにより、Djangoは新しいディレクトリとより多くのファイルをプロジェクトに追加しました。

最新のファイルを生成したら、weatherアプリディレクトリにurls.pyという新しいファイルを作成しましょう。

the_weather / Weather / urls.py
from django.urls import path

urlpatterns = [
]

このファイルは、the_weatherディレクトリのurls.pyに似ています。 違いは、このurls.pyファイルには、アプリ自体に関連するすべてのURLが含まれていることです。

まだURLを指定していませんが、アプリを認識し、アプリに固有のURLをアプリurls.pyファイルにルーティングするようにプロジェクトを設定できます。

まず、settings.pyINSTALLED_APPSリストに移動し、weatherをリストに追加します。

the_weather / the_weather / settings.py
...

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'weather',
]

...

これにより、Djangoはプロジェクトでweatherアプリを使用することを認識できます。 これを行うことで、Djangoは移行とURLを探す場所を知ることができます。

次に、元のurls.pyを変更して、アプリのurls.pyファイルを指すようにする必要があります。 これを実現するには、管理ダッシュボードの既存のパスの下に行を追加します。 また、アプリのurls.pyファイルをポイントできるように、includeをインポートする必要があります。

the_weather / the_weather / urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('weather.urls')),
]

空の文字列は、アプリへのエントリポイントにエンドポイントを使用する必要がないことを意味します。 代わりに、アプリに特定のエンドポイントを処理させます。 path('weather/', ...)のようなものを配置することもできます。つまり、天気アプリに関連付けられているものを取得するには、127.0.0.1:8000/weather/と入力する必要があります。 ただし、プロジェクトは単純なので、ここではそれを行いません。

ステップ5—テンプレートとビューを追加する

次に、テンプレートをプロジェクトに追加する必要があります。

Djangoのtemplateは、テンプレートを動的にする追加の構文を可能にするHTMLファイルです。 変数の追加、ifステートメント、ループなどの機能を処理できるようになります。

ターミナルで、weatherアプリディレクトリに移動します。

  1. cd weather

次に、templatesディレクトリを作成します。

  1. mkdir templates

そしてそれにナビゲートします:

  1. cd templates

また、アプリと同じ名前の別のディレクトリを作成します。 これは、Djangoがさまざまなアプリのすべてのテンプレートディレクトリを組み合わせているためです。 ファイル名が重複しないようにするには、アプリの名前を使用して重複を防ぐことができます。

  1. mkdir weather

このweatherディレクトリ内に、index.htmlという名前の新しいファイルを作成します。 これがメインテンプレートになります。

テンプレートに使用するHTMLは次のとおりです。

the_weather /weather/templates/weather/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>What's the weather like?</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.2/css/bulma.css" />
</head>
<body>
    <section class="hero is-primary">
        <div class="hero-body">
            <div class="container">
                <h1 class="title">
                    What's the weather like?
                </h1>
            </div>
        </div>
    </section>
    <section class="section">
        <div class="container">
            <div class="columns">
                <div class="column is-offset-4 is-4">
                    <form method="POST">
                        <div class="field has-addons">
                            <div class="control is-expanded">
                                <input class="input" type="text" placeholder="City Name">
                            </div>
                            <div class="control">
                                <button class="button is-info">
                                    Add City
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </section>
    <section class="section">
        <div class="container">
            <div class="columns">
                <div class="column is-offset-4 is-4">
                    <div class="box">
                        <article class="media">
                            <div class="media-left">
                                <figure class="image is-50x50">
                                    <img src="http://openweathermap.org/img/w/10d.png" alt="Image">
                                </figure>
                            </div>
                            <div class="media-content">
                                <div class="content">
                                    <p>
                                        <span class="title">Las Vegas</span>
                                        <br>
                                        <span class="subtitle">29° F</span>
                                        <br> thunderstorm with heavy rain
                                    </p>
                                </div>
                            </div>
                        </article>
                    </div>
                </div>
            </div>
        </div>
    </section>
    <footer class="footer">
    </footer>
</body>
</html>

注:舞台裏では、ブルマを使用してスタイリングとレイアウトを処理しています。 ブルマとCSSフレームワークの詳細については、ブルマを知る:私の現在のお気に入りのCSSフレームワークを読むことを検討してください。

テンプレートを作成したので、ビューとURLの組み合わせを作成して、アプリで実際にこれを確認できるようにします。

DjangoのViewsは、関数またはクラスのいずれかです。 この場合、単純なビューを作成しているので、関数を作成します。 この関数をviews.pyファイルに追加します。

the_weather / Weather / views.py
from django.shortcuts import render

def index(request):
    return render(request, 'weather/index.html') #returns the index.html template

ビューにindexという名前を付けているのは、ルートURLであるアプリのインデックスにあるためです。 テンプレートをレンダリングするには、render関数に必要なrequestと、レンダリングするテンプレートファイルの名前(この場合はweather/index.html)を返します。 。

このビューにリクエストを送信するURLを追加しましょう。 アプリのurls.pyファイルで、urlpatternsリストを更新します。

the_weather / Weather / urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.index),  #the path for our index view
]

これにより、作成したばかりのビューを参照できます。

Djangoは、エンドポイントのない任意のURLと一致し、作成したビュー関数にルーティングします。

次に、ターミナルを使用してプロジェクトルート(the_weather)に戻ります。

次に、サーバーを起動します。

  1. python manage.py runserver

次に、Webブラウザーを開き、127.0.0.1:8000に再度アクセスします。

Browser window depicting View with hard-coded values for Las Vegas

index.htmlファイルのレンダリングされたHTMLを観察します。 都市を追加するための入力があります。 そして、ラスベガスのハードコードされた天気の表示があります。 ただし、この時点でのフォームは機能せず、天気は単なるプレースホルダーです。 次はそれに取り組みましょう。

ステップ6—WeatherAPIを使用する

ここで実行したいのは、 Open Weather MapAPIにサインアップすることです。 これにより、アプリに追加した都市の天気をリアルタイムで取得できます。

サイトに移動し、アカウントを作成してから、ダッシュボードのAPIキーに移動します。 提供されているデフォルトキーを使用することも、新しいAPIキーを作成することもできます。 このキーを使用すると、APIを使用して天気を取得できます。

Open Weather Map Dashboard

注: APIキーを秘密にして、他のユーザーが使用できないようにすることが重要です。 APIキーをGitHubなどのリモートリポジトリにコミットしないようにする必要があります。

使用するエンドポイントの1つは以下のとおりです。そのため、APIキーを使用して次のURLを変更し、ブラウザでURLに移動すると、返されるデータを確認できます。

http://api.openweathermap.org/data/2.5/weather?q=las%20vegas&units=imperial&appid=YOUR_APP_KEY

APIキーがアクティブになるまでに数分かかる場合があるため、最初に機能しない場合は、数分後に再試行してください。

座標、温度、気象条件を含むJSON形式の応答が表示されます。

それでは、データをアプリに取り込むためのリクエストを追加しましょう。

indexビューを更新して、お持ちのURLにリクエストを送信しましょう。

the_weather / Weather / views.py
from django.shortcuts import render
import requests

def index(request):
    url = 'http://api.openweathermap.org/data/2.5/weather?q={}&units=imperial&appid=YOUR_APP_KEY'

    city = 'Las Vegas'

    city_weather = requests.get(url.format(city)).json() #request the API data and convert the JSON to Python data types

    return render(request, 'weather/index.html') #returns the index.html template

import requestsurlcity、およびcity_weatherを追加します。

これらの新しい行を使用して、リクエストの送信先となるURLを追加します。

このURLは、以前にブラウザでテストしたURLとは少し異なることに注意してください。 都市はURLの一部ではなく、変数に移動されました。 このパターンにより、将来的に他の都市名に置き換えることができます。

今のところ、都市を「ラスベガス」に設定しますが、後でデータベースから都市に設定します。

最後に、都市を使用してURLにリクエストを送信し、その都市のJSON表現を取得します。

printをコンソールに表示すると、アドレスバーにURLを入力したときに表示されたのと同じデータが表示されます。

the_weather / Weather / views.py
...
def index(request):
    ...
    print(city_weather) #temporarily view output

    return render(request, 'weather/index.html') #returns the index.html template

Webブラウザーでページをリロードすると、データがコンソールに出力されます。

これが真であることが確認されたら、コードからprintステートメントを削除できます。

ステップ7—テンプレートにデータを表示する

次に、データをテンプレートに渡して、ユーザーに表示できるようにする必要があります。

必要なすべてのデータを保持する辞書を作成しましょう。 返されるデータのうち、tempdescription、およびiconが必要になります。

the_weather / Weather / views.py
...
def index(request):
    ...
    weather = {
        'city' : city,
        'temperature' : city_weather['main']['temp'],
        'description' : city_weather['weather'][0]['description'],
        'icon' : city_weather['weather'][0]['icon']
    }

    return render(request, 'weather/index.html') #returns the index.html template

必要な情報がすべて揃ったので、それをテンプレートに渡すことができます。 これをテンプレートに渡すには、contextという変数を作成します。 これは、テンプレート内でその値を使用できるようにする辞書になります。

次に、renderで、3番目の引数としてcontextを追加します。

the_weather / Weather / views.py
...
def index(request):
    ...
    context = {'weather' : weather}

    return render(request, 'weather/index.html', context) #returns the index.html template

context内に気象データを追加したら、テンプレートに移動してデータを追加しましょう。

index.htmlテンプレート内で行う必要があるのは、ハードコードされた値の代わりに変数を使用するようにHTMLを変更することだけです。 変数は{{}}タグを使用し、コンテキストディクショナリ内のすべてを参照します。

Djangoは辞書キーを変換するため、ドット表記を使用してのみアクセスできることに注意してください。 たとえば、weather.cityは都市名を示します。 Pythonのようにweather['city']を使用することはありません。

「ボックス」<div>を見つけて、変数を使用するように更新します。

the_weather /weather/templates/weather/index.html
...
<div class="box">
    <article class="media">
        <div class="media-left">
            <figure class="image is-50x50">
                <img src="http://openweathermap.org/img/w/{{ weather.icon }}.png" alt="Image">
            </figure>
        </div>
        <div class="media-content">
            <div class="content">
                <p>
                    <span class="title">{{ weather.city }}</span>
                    <br>
                    <span class="subtitle">{{ weather.temperature }}° F</span>
                    <br> {{ weather.description }}
                </p>
            </div>
        </div>
    </article>
</div>
...

すべての変数が置き換えられると、都市の現在の天気が表示されます。

Browser window depicting dynamic weather for Las Vegas

ただし、都市は現在もハードコーディングされています。 次に実行したいのは、データベースからプルして、データベースにある都市を表示することです。

これを実現するには、データベースにテーブルを作成して、天気を知りたい都市を保持します。 このためのモデルを作成します。

weatherアプリのmodels.pyファイルに移動し、次を追加します。

the_weather / Weather / models.py
from django.db import models

class City(models.Model):
    name = models.CharField(max_length=25)

    def __str__(self): #show the actual city name on the dashboard
        return self.name

    class Meta: #show the plural of city as cities instead of citys
        verbose_name_plural = 'cities'

これにより、都市の名前であるnameという列を持つテーブルがデータベースに作成されます。 この都市はcharfieldになります。これは単なる文字列です。

データベースでこれらの変更を取得するには、makemigrationsを実行して、データベースを更新するコードを生成し、移行してこれらの変更を適用する必要があります。

サーバーを停止してから、ターミナルで移行を実行しましょう。

  1. python manage.py makemigrations

そして移行します:

  1. python manage.py migrate

管理ダッシュボードでこのモデルを表示できるようにする必要があります。 これを行うには、admin.pyファイルに登録する必要があります。

the_weather / Weather / admin.py
from django.contrib import admin
from .models import City

admin.site.register(City)

次に、サーバーを再起動し、Webブラウザーで管理ダッシュボードを表示します。

Browser window depicting cities on the Admin Dashboard

Cityがオプションになりました。

次に、管理ダッシュボードに移動して、いくつかの都市を追加できます。 例:「ロンドン」、「東京」、「ラスベガス」。

Browser window depicting three cities added to database

データベース内のエントリを使用して、ビューでこれらのエントリをクエリする必要があります。 Cityモデルをインポートしてから、そのモデルにすべてのオブジェクトを照会することから始めます。

the_weather / Weather / views.py
from django.shortcuts import render
import requests
from .models import City

次に、requestcitiesで更新します。

the_weather / Weather / views.py
...
def index(request):
    url = 'http://api.openweathermap.org/data/2.5/weather?q={}&units=imperial&appid=YOUR_APP_KEY'

    cities = City.objects.all() #return all the cities in the database
    ...

都市のリストがあるので、それらをループして各都市の天気を取得し、最終的にテンプレートに渡されるリストに追加する必要があります。

これは、前のステップで行ったことのバリエーションにすぎません。 違いは、各辞書をループしてリストに追加することです。

まず、[X21X]