はじめに

こんにちは。22年新卒のN.Aです!

前回の第3弾の記事はご覧いただけましたでしょうか?
第1弾~第3弾では環境構築からログイン画面の実装、また、Bootstrapを使った画面デザインの整え方について学んできました。
そして、第4弾となる今回はいよいよLunchBoxの基本機能の1つである「タイムライン画面」の実装に入っていきたいと思います!

今回初めてご覧いただいた方は「LunchBoxとは?」という疑問を抱かれたかと思いますので、ぜひ第1弾のこちらの記事からご覧いただければと思います。

今回の目次

1.タイムライン画面とは?
2.データベースにテーブルを追加してみよう!
3.テストデータを登録してみよう!
4.データベースの値を画面に表示してみよう!
5.Bootstrapを使って画面を整えよう!
6.今回はここまで!さいごに

1.タイムライン画面とは?

まずはじめに、今回作成するタイムライン画面の概要について説明いたします。
説明の前に、イメージをもっていただきたいので、まずは完成図からご覧ください!
今回の内容を実践していただければ下の画像のような画面が完成する予定となっております。

タイムライン画面とは、”自分と同じコミュニティに所属する全てのユーザーのランチ日記を
時系列順に表示する画面”です。
インスタグラムを利用されている方であれば、インスタグラムのタイムライン画面をイメージ
していただければいいと思います!
表示されているランチ日記をクリックすると、そのランチ日記の内容の詳細画面に遷移します。

それでは早速、画面実装の準備に入っていきましょう!

2.データベースにテーブルを追加してみよう!

タイムラインに表示されるまでの流れは以下のようになっています。

①ランチ日記投稿フォームにランチの情報を記入し投稿
②データベースに投稿内容が保存される
③全てのユーザーのランチ日記をデータベースから取ってきて一覧表示する

投稿フォームの作成や投稿機能の実装については第5回の記事で扱うので、今回はデータベースに
手動でテストデータを入れて表示させるという方法でタイムライン画面を作成していきます!

データベースとの連携に必要になってくるのがモデル(Model)です。
モデルとは、Webアプリケーションとデータベースを連携させる仕組みのことです。
モデルはデータベースに格納されているデータにアクセスすることができます。
Djangoではモデルを使うことにより、データベースからデータの検索・取得・追加・削除といった操作を簡単に行うことができます。

モデルの作成には次のようなルールと特徴があります。

・各アプリケーション内のmodels.pyを使用する
・1つのモデルが1つの(データベース内の)テーブルと対応する
・Pythonのクラスであり、django.db.models.Modelのサブクラス
・モデル名は大文字で始める
・idフィールドは自動的に追加される(Primary keyを定義しない場合)
・フィールドのオプションで何も指定しなければNOT NULL制約がかかる

それでは、実際にモデルを作成していきます。
今回、タイムラインを表示させるのには新たに2つのテーブル(lunchDiary_informationテーブル、lunch_costテーブル)が必要なので、それぞれモデルを作成します。

まずはcostモデルの作成から説明します。
このcostモデルにはランチの料金の価格帯が入ります。以下画像のようなイメージです。

lunch_costモデルを作成するために、models.pyと同じ階層にlunchCostModel.pyというモデルファイルを作成します。

画像に alt 属性が指定されていません。ファイル名: image-8.png

モデルを定義するには、モデルの中身を書く前にdjango.db.modelsをインポートします。

続いて、モデルの中身を書いていきます。
モデルはdjango.db.models.Modelを継承して定義します。
「class クラス名(models.Model):」に続けて、必要なフィールドを記載していきます。
フィールドはデータベースのカラムに相当するので、必要なカラム名をここで一旦整理しましょう。

lunch_costモデルに必要なカラムは「価格帯」のみなので、
・価格帯→cost_range
のみ定義します。

型についての説明等は後ほど行いますので、今は一旦これで、lunch_costモデルの作成は完了です。

続いて、LunchDiary_informationモデルの作成をします。
LunchDiary_informationの作成はファイルはアプリケーションフォルダ(LunchBox)に自動生成されたmodels.pyを使います。

先ほどと同様に、モデルの中身を書く前にdjango.db.modelsをインポートします。

続いて、モデルの中身を書いていきます。

タイムライン画面を表示するのに必要な情報は「ランチの画像・お店の名前・メニュー名・値段・投稿者名」の5項目ですが、投稿フォーム機能の作成の際に同じテーブルを利用できるよう、投稿フォームで使う全ての項目を用意しておきます。

各項目は次のように定義します。

・投稿者のid→post_user
・ランチの写真→dish_image
・メニュー名→dish_name
・ジャンル→genre
・店名→restaurant_name
・値段→cost
・提供時間→serving_time
・イートインかテイクアウトか→style
・メモ→memo
・評価→evaluation
・来店日時→visited_time
・投稿日時→created_time

上記の内容を反映させたものがこちらになります。

models.IntegerField()のIntegerFieldの部分ではフィールドの型を設定しています。
Djangoに用意されているフィールドの型は様々ですが、今回使用したものは以下の通りです。

・IntegerField→整数
・ImageField→画像
・CharField→文字列
・DateTImeField→日時

型によって扱えるデータが異なるので、フィールドごとに適した型を設定する必要があります。
ここで、post_userやcostに設定されているForeignKeyってなんだろうと疑問に思った方もいる
のではないでしょうか?

こちらは上記の型とは少し扱いが異なるので説明します。
まず、複数のモデル間(テーブル間)を紐づけるフィールドをリレーションフィールドと言い、
ForeignKeyもその一つです。
ForeignKeyは他モデルと多対一のリレーションを持つフィールドを作成します。

ForeignKeyには2つの引数(to, on_delete)を必ず指定する必要があります。
toには紐づけるモデルを指定し、on_deleteには親フィールドが削除されたときの動作を指定します。
「1」になるモデルが親、「多」になるモデルが子の関係となり、ForeignKeyのフィールドは子側に
作成します。
今回の例で言うと、lunch_costモデルが親、lunchdiary_informationモデルが子になります。

投稿者が投稿フォームで価格帯を選択し、投稿するとlunchdiary_informationテーブルのcost_idには価格帯のidが入ります。
そのまま表示してしまうと、画面にidの数字が表示されてしまうので、lunch_costテーブルを参照し、そのidの価格帯を引っ張ってくる必要があります。
このlunchdiary_informationテーブルとlunch_costテーブルを紐づけるのがcostカラムになるので、ここにForeignKeyを設定することで、lunchdiary_informationモデルからlunch_costモデルを参照することが可能になります。

そしてこのForeignKeyはon_deleteというフィールドオプションによって、参照先のフィールドのレコードが削除された場合の動作を指定することができます。
・models.CASCADE→親データが削除されると結びついている子データも削除される
・models.SET_NULL→親データが削除されると子データにNullをセットする

これでLunchDiary_informationモデルの作成は完了です。

続いて作成したモデルをデータベースに反映させます。

第2弾の復習になりますが、modelファイルをデータベースに反映するためにはマイグレーションが必要です。ターミナルで「manage.py」のあるフォルダへ移動し、下記のcommandを実行してください。

python manage.py makemigrations

マイグレーションファイルが作成されているはずです。

次に以下のコマンドでマイグレートを実行します。

python manage.py makemigrate

これで、LunchDiary_informationテーブルとlunch_costテーブルが作成できました!

3.テストデータを登録してみよう!

今回はデータベースの情報を取ってきてタイムライン画面に表示させるということを行いたいので、データベースに手動でテストデータを入れます。

Djangoには、初期データを登録するのに便利なfixtureという機能が備わっています!
まず、fixtureファイルを保存するためのディレクトリを作成します。
fixture用のディレクトリは各アプリケーション内に作成するという決まりがあるため、下記のようにアプリケーションフォルダー(LunchBox)の直下にfixturesディレクトリを作成してください。

ディレクトリを作成したら、その中にfixtureファイルを作成しましょう。
fixtureファイルはxml、yaml、jsonで作成することが可能ですが、今回はjsonファイルで作成します。
ファイルの中身にはランチ日記のテストデータを入れるので、ファイル名はlunchdiary_information_init.jsonとします。

次にfixtureファイルの中身を書いていきます。
ここには、追加したいテーブルとカラム名、テストデータ等を記載します。
まずはlunchDiary_informationテーブルから行います。

modelにはアプリケーション名.モデル名を記載します。
pkはプライマリーキーのことで、idのことを指しています。また、fieldsのオブジェクトの中にはテーブルのカラム名を指定し、テストデータを記述します。
タイムラインを表示させるのにランチ日記6つ分くらいのデータがあると見た目が分かりやすいので、{ }の中身を複製して、6つ分のランチ日記のデータを作成してください。

同様に、lunch_costテーブルのテストデータを作ります。

fixtureファイルの作成が終わったら、再びターミナルでmanage.pyのあるフォルダに移動して下記コマンドを実行します。

python manage.py loaddata lunchdiary_information_init.json

コマンドが問題なく通れば、データベースに初期データが生成されています。
以上でデータベースにテストデータを入れる作業は完了しました!

続いて、データベースに登録したデータを画面上に表示させる手順を説明いたします!

4.データベースの値を画面に表示してみよう!

まずはサーバー側の処理を記述します。
timeline.Views.pyを開き、先ほど作ったモデルをインポートします。

インポートすることで、LunchDiary_informationモデルがtimeline.Vies.pyの中で使えるようになります。

続いて、タイムラインの初期表示をするdef timeline_view(request):の中身を書き足します。

【timeline.Views.py】

Djangoにはクエリセットメソッドという便利なメソッドが用意されており、「モデルクラス名.objects」と記述することで簡単にデータベースにアクセスすることができます。
ちなみに、クエリセットとはモデルのデータベースから取り出したデータリストのことです。
クエリセットメソッドの中でもよく使われるのが「objects.all()」メソッドです。
モデルクラス名.objects.all()」とすることでクエリセットの全てをコピーして出力してくれます。
タイムライン画面のようにデータベース上のデータ全てを一覧表示する際などによく使われるので覚えておきましょう!

今回は、LunchDiary_information.objects.all()で、Lunchdiary_informationモデルの取得したリストを全て取ってきて、lunch_infoという変数に入れています。

Viewで作成した変数をtemplateファイルに渡して表示するのにはcontextで辞書型のデータに入れ込みます。こうすることで、html側では{{ }}で囲むだけで表示することができます。
※このとき、renderをインポートしてある必要があるので、

の記述があることを確かめてください。

ここまで出来たらフロント側を作っていきます。
templateフォルダの中にあるtimeline.htmlファイルの中に次のように記述します。

timeline.html

第2弾の記事でも説明がありましたが、{% extends “base.html” %}で全画面に共通するベースのhtmlを継承しています。

<!–日記表示エリア–>以下ではデータベースに登録されている全てランチ日記のデータを一つずつ表示させていきたいので{% for lunch in lunch_info %}{% endfor %}でforタグを使い、繰り返し処理を行います。

ここでcontextに入れたlunch_infoがでてきました。
{% for lunch in lunch_info %}ではlunch_infolunchに取り出すという処理を、データがある限り繰り返すということを表しています。

そして、{{ lunch.restaurant_name }}は取り出したlunchの中のrestaurant_nameカラム内のデータを表示させているという仕組みになっています。
lunchdiary_informationテーブルのデータを一行ずつ取り出し、必要なカラムのデータを表示させるということをテーブルの行数分行っているようなイメージです!

ただし、画像の表直接示は処理が異なるので、ランチの写真に関しては、今回は一旦データベースは使わずに表示させておきます。
フォルダに画像を保存し、そのフォルダのパスから画像を引っ張ってくるという方法で行うので、まず、画像を入れるフォルダを用意します。

staticフォルダの中に、imagesというフォルダを作成してください。

次に任意の画像を一つ用意し、先ほど作ったimagesフォルダの中に入れます。
私はno_image.jpgという画像を用意しました。


この画像を表示させている部分がtimeline.htmlの以下の部分になります。

<img src=”{% static ‘images/no_image.jpg’ %}” alt=”dish_image” style = “max-width:100%; max-height:100%;”>

画像を表示させる<img>タグの中には画像が入っているフォルダまでのパスを指定する必要があります。
今回はstaticファイルの中に入れているので{% static ‘images/no_image.jpg’ %}でパスを指定できています。
このstaticについての説明は第2弾でcssの読み込みをする際に行っているので、よろしければご覧ください。

ここまで出来たら、画面を確認してみましょう。これまで何度か出てきましたが、ターミナルでmanage.pyのあるフォルダに移動して下記コマンドを実行します。

>python manage.py runserver

上の画像のような表示になりましたでしょうか?
今は左に縦一列にデータが並んでいますが、タイムラインらしく、横に3つずつランチ日記を並べていきたいので、第3弾で学んだBootstrapを利用して画面を整えていきましょう!

5.Bootstrapを使って画面を整えよう!

それでは早速Bootstrapを使っていくのですが、Bootstrapの概要や使い方については第3弾の記事で詳しく説明しているので、確認したいという方はこちらをご覧ください。

Bootstrapを使うためにはソースファイルをダウンロードするかCDN(Contents Delivery Network)という方法を使ってセットアップを行う必要がありますが、第3弾の記事でbase.htmlにCDNでのセットアップを行っています。

base.htmlはすべての画面で読み込みが行われているため、今回実装するtimeline.htmlで改めてセットアップを行わなくても、Bootstrapが適用できる状態になっています!

先ほど作成したtimeline.htmlの<div>タグの中に以下のようにclassを追加してみてください。

【timeline.html】

また、lunchbox.cssにcssを一つ追加してください。

【lunchbox.css】

記載したBootstrapのクラスについて簡単に説明します。

まず、この<div>タグはランチ日記が表示されているエリア全体を囲っているタグになります。

d-flex…フレックスボックスを指定。
flex-row…フレックスボックスの方向を「横並び」に指定。
mb-2…mb-○○で下のマージンを指定。mb-1がスペース×0.25の幅になるので、mb2はスペース×0.5の幅。
border…ボーダーを表示。
flex-wrap…フレックスアイテムの折り返しを指定。上から下に折り返され、2行目以降のアイテムは左から右に配置される。

containerは今回唯一BootStrapではなく、cssでマージンを指定するために自分でつけたクラスで、追加していただいたlunchbox.cssで指定を行っています。
このlunchbox.cssはbase.htmlですでに読み込みを行っており、timeline.htmlはそのbase.htmlを読み込んでいるので、改めてcssの読み込みを行う必要はありません。

これはランチ日記一つ分を囲うタグになります。

card…サムネイル画像、見出し、テキスト、リンクなどを内包することができる「カード」というコンポーネントを指定。
col-4…col-○○は画面の横幅を12等分に分割し、そのうち何個分を幅として使用するかを指定。(3つの投稿を横並びにしたいので12÷3で一つの投稿あたり4個分という計算。)

投稿の料理の画像の部分を囲っているタグになります。

h-50…h-○○でコンテンツの高さを指定。○○の部分が%になるので、この場合、50%を指定。
d-inline-block…インラインブロックとして表示することを指定。

こちらは店名・商品名・値段といったランチ日記の中身を表示する部分です。

card-body…先ほど指定したcardのコンテンツ部分であるということを示している。

ここまで出来たら画面を見てみましょう!

投稿が横に3つずつ表示され、タイムライン画面らしくなりました。

6.今回はここまで!さいごに

最後までご覧いただきありがとうございました!
今回の内容いかがだったでしょうか?
タイムライン画面はパッと見、情報量が多いので、実装が難しそうに感じますが、今回のような場合は、
データベース内にあるランチ日記の情報が入ったテーブルからデータをすべて取得し、順番に表示させて
いるだけなので、それほどコードを記載しなくても出来てしまうんです!
また、データベースにテーブルを追加したり、カラムを変更したい場合は、Modelを書き換えれば簡単に
できるのでとても便利です。(その際、マイグレーションを忘れずに!)
今回の内容を少し応用させれば、特定のユーザーが投稿したランチ日記情報のみ取得して表示させたり、
ランチ日記のジャンルで検索をかけるといった機能も実装することができます。

タイムラインの表示ができたことで少しずつLunchBoxがアプリらしくなってきました。
引き続きLunchBoxの機能を充実させていきましょう!
次回の第5弾もお楽しみに!

N.A
SD部 N.A
プログラミング未経験で入社しました!