簡易書籍アプリケーション(CRUD)の説明

6.6 簡易書籍アプリケーション(CRUD)の説明

作成したアプリケーションをもとに、データベースアクセス処理が実際どのような流れで動作しているのかを説明していきます。

6.6.1 登録機能(Create)

まず入力したデータを登録する登録機能について確認していきましょう。

urls.py

最初に「bmsdjango」ディレクトリの「urls.py」を確認すると、「http://localhost:8000/bmsdjango/insert」にアクセスすると「insert」に該当する要素として、「insert関数」が実行されることがわかります。

■ソースコード
【ファイル名:bmsdjango/urls.py】

View(view.py)

「http://localhost:8000/bmsdjango/insert」にアクセスすると、「insert関数」が実行されることがわかりました。
続いてViewに該当する、insert関数の処理を確認していきましょう。

■ソースコード
【ファイル名:bmsdjango/views.py】

17~32行目ではif else文が実行されています。17行目の「if (request.,method == ‘POST’)」はHTTPリクエストメソッドが、「POST」かどうかを判定するためのものです。

POST送信が実行された(true)場合、18~28行目、そうでない(false)場合は32行目が実行されます。

POST送信が行われなかった場合、http://localhost:8000/bmsdjango/insert」にアクセスすると「insert.html」が表示されるのがわかります。

図 6.6 1:http://localhost:8000/bmsdjango/insertにアクセスした場合の表示結果

■ソースコード
【ファイル名:insert.html】

1{%load static%}
2<!DOCTYPE html>
3<html>
4    <head>
5        <meta charset="UTF-8">
6        <title>書籍登録</title>
7        <link rel="stylesheet" type="text/css" href="{% static 'style.css' %}"/>
8    </head>
9    <body>
10        <!-- ブラウザ全体 -->
11        <div id="wrap">
12 
13            <!--ヘッダー部分-->
14            <header>
15                <div class="container">
16                    <h1>書籍管理システムSpring版 Ver.1.0{{test}}</h1>
17                </div>
18            </header>
19 
20            <!-- メニュー部分 -->
21            <div id="menu">
22                <div class="container">
23                    <!-- ナビゲーション  -->
24                    <div id="nav">
25                        <ul>
26                            <li><a href="./">[メニュー]</a></li>
27                            <li><a href="{% url 'insert' %}">[書籍登録]</a></li>
28                            <li><a href="{% url 'list' %}">[書籍一覧]</a></li>
29                        </ul>
30                    </div>
31 
32                    <!-- ページタイトル -->
33                    <div id="page_title">
34                        <h2>書籍登録</h2>
35                    </div>
36                </div>
37            </div>
38 
39            <!-- 書籍一覧のコンテンツ部分 -->
40            <div id="main" class="container">
41                <!--入力フォーム -->
42                <form action="{% url 'insert' %}" method="POST">
43                    {% csrf_token %}
44                    <table class="input-table" align="center">
45                        <tr>
46                            <th>ISBN</th>
47                            <td>
48                                <input type="text" name="isbn">
49                            </td>
50                            </tr>
51                        <tr>
52                            <th>TITLE</th>
53                            <td>
54                                <input type="text" name="title">
55                            </td>
56                        </tr>
57                        <tr>
58                            <th>価格</th>
59                            <td>
60                                <input type="text" name="price">
61                            </td>
62                        </tr>
63                    </table>
64                    <input type="submit" value="登録">
65                </form>
66            </div>
67 
68            <!-- フッター部分 -->
69            <footer>
70                <div class="container">
71                    <h4>Copyright&copy; 2018 All Right Reserved.</h4>
72                </div>
73            </footer>
74 
75        </div>
76    </body>
77</html>

続いてPOST送信が実行された場合の処理を確認していきますが、POST送信はどのようなタイミングで行われるのかを確認しましょう。
「insert.html」の42行目を確認すると、「action=”{% url ‘insert’ %}”」から入力フォームを送信(登録ボタンをクリック)すると、「http://localhost:8000/bmsdjango/insert」に遷移するため、再び「insert関数」が実行されることがわかります。

■ソースコード
【ファイル名:insert.html】

1<form action="{% url 'insert' %}" method="POST">

またこの入力フォームは42行目の「method=”POST”」からPOST送信が実行されるため、遷移先のinsert関数では、POST送信が実行された場合の処理として18~28行目の処理(trueの場合)が実行されることがわかります。

図 6.6 2:POST送信後の流れ

では「insert.hml」にてPOST送信が行われた値の処理、つまりはinsert関数の
17行目「if (request.method == ‘POST’):」の判定がtrueだった場合の、18~28行目の処理を確認していきましょう。

【ファイル名:bmsdjango/views.py】

1if (request.method == 'POST'):
2    #POSTデータを受け取る
3    isbn = request.POST["isbn"]
4    title = request.POST["title"]
5    price = request.POST["price"]
6 
7    #入力した値をDBに保存
8    book = Book(isbn=isbn,title=title,price=price)
9    book.save()
10 
11    #listにリダイレクト
12    return redirect(to='./list')

まず19~22行目の「request.POST[“●●●”]」は、「insert.html」の「42~65行目」の入力フォームにおける送信データを受け取るためのものです。

1isbn = request.POST["isbn"]
2title = request.POST["title"]
3price = request.POST["price"]

■ソースコード
【ファイル名:insert.html】

具体的には、「<input type=”text” name=”isbn”>」で入力されたデータを、「request.POST[“isbn”]」で受け取り、「<input type=”text” name=”title”>」で入力されたデータを、「request.POST[“title”]」で受け取り、「<input type=”text” name=”price”>」で入力されたデータを、「request.POST[“price”]」で受け取ります。

図 6.6 3:送信データの受け取り

続いて24行目、25行目を確認すると、24行目ではPOST送信で受け取った各値を引数に、Bookクラスのインスタンスを作成し、変数bookに代入します。
さらに25行目では、インスタンスを介して「saveメソッド」が実行されます。

1#入力した値をDBに保存
2book = Book(isbn=isbn,title=title,price=price)
3book.save()

Modelのインスタンスはsaveメソッドを実行すると、インスタンス作成時に指定した引数がそのままデータベースに登録されます。
つまりはBookテーブルのisbn列に変数isbnの値、title列に変数titleの値、price列にpriceの値が登録されます。

図 6.6 4:送信データの受け取り

最後、28行目ではredirectメソッドを使用します。redirectメソッドは強制的にリダイレクト(他のページへ転送)させるためのものです。

1#listにリダイレクト
2return redirect(to='./list')

遷移先のページは引数toに値を設定します。今回、「’/list’」が設定されているので、「http://localhost:8000/bmsdjango/list」へリダイレクトされます。

6.6.2 更新機能(update)

続いて登録済みのデータを変更する更新機能について確認していきましょう。

urls.py

最初に「bmsdjango」ディレクトリの「urls.py」を確認すると、「bmsdjango」ディレクトリ下の「urls.py」を確認すると、「http://localhost:8000/bmsdjango/update/●●●」にアクセスすると「update/●●●」に該当する要素として、「update関数」が実行されることがわかります。

■ソースコード
【ファイル名:bmsdjango/urls.py】

また「path(‘update/<str:isbn>’, views.update, name=’update’)」で指定されている「update/<str:isbn>」の「<str:isbn>」は、「http://localhost:8000/bmsdjango/update/●●●」にアクセスがあった場合、●●●を文字列(str)としてisbnに格納され、呼び出し先の関数updateに引き渡されます。

例えば「http://localhost:8000/bmsdjango/update/0005」にアクセスがあった場合、update関数が呼び出され、「0005」がisbnに格納された状態でuprdate関数に引き渡されるということです。

図 6.6 5:update関数呼び出しの流れ

View(view.py)

「http://localhost:8000/bmsdjango/update/●●●」にアクセスすると、「update関数」が、●●●の値がisbnに格納された状態で引き渡された上で実行されることがわかりました。
そこでupdate関数の処理を確認していきましょう。

■ソースコード
【ファイル名:bmsdjango/views.py】

1def update(request,isbn):
2    #特定のレコードを取得
3    book = Book.objects.get(isbn=isbn)
4 
5    #POST送信の確認
6    if (request.method == 'POST'):
7        #POSTデータの値を更新する
8        book.title = request.POST["title"]
9        book.price = request.POST["price"]
10        book.save()
11        #listにリダイレクト
12        return redirect(to='list')
13    else:
14        params ={
15            'book':book,
16        }
17        #Templateを表示させる
18        return render(request, 'update.html',params)

48行目では、引数isbnを従えていますが、こちらは先ほどのupdate関数を呼び出す段階で、引き渡されたisbnの値(「http://localhost:8000/bmsdjango/update/●●●」における●●●)がそのまま代入されます。

続いて50行目では、Bookクラスを介してobjects.get()メソッドを呼び出しています。getメソッドの引数には該当するテーブルの列名(今回のケースではisbn)を従えます。

引数に設定した値を検索値としてテーブル内に対象の列に値が存在すれば、該当の行の各列の値を従えたModel(Bookクラス)のインスタンスが生成されます。

今回のケースでは「get(isbn=isbn)」なので、isbn列が変数isbnに該当する行の各列の値を従えたBookクラスのインスタンスが生成されます。

図 6.6 6:filterメソッドの動き

53~65行目ではif else文が実行されていています。
先ほどと同様、53行目の「if (request.,method == ‘POST’)」はHTTPリクエストメソッドが、「POST」かどうかを判定するためのものです。

POST送信が実行された(true)場合、54~59行目、そうでない(false)場合は61~65行目が実行されます。
まずPOST送信が実行されなかった場合(false)の処理を確認していきましょう。

1else:
2    params ={
3        'book':book,
4    }
5    #Templateを表示させる
6    return render(request, 'update.html',params)

50行目で宣言した変数bookを引き渡す形で、Templateとして「update.html」が呼び出されることが確認できます。
つまりはPOST送信が行われなかった場合、「http://localhost:8000/bmsdjango/update/●●●」にアクセスすると「update.hml」が表示されるのがわかります。

では「update.html」の中身がどのなっているのかを確認していきましょう。

■ソースコード
【ファイル名:update.html】

1{%load static%}
2<!DOCTYPE html>
3<html>
4    <head>
5        <meta charset="UTF-8">
6        <title>書籍一覧</title>
7        <link rel="stylesheet" type="text/css" href="{% static 'style.css' %}"/>
8    </head>
9    <body>
10        <!-- ブラウザ全体 -->
11        <div id="wrap">
12 
13            <!--ヘッダー部分-->
14            <header>
15                <div class="container">
16                    <h1>書籍管理システムSpring版 Ver.1.0{{test}}</h1>
17                </div>
18            </header>
19 
20            <!-- メニュー部分 -->
21            <div id="menu">
22                <div class="container">
23                    <!-- ナビゲーション  -->
24                    <div id="nav">
25                        <ul>
26                            <li><a href="./">[メニュー]</a></li>
27                            <li><a href="{% url 'insert' %}">[書籍登録]</a></li>
28                            <li><a href="{% url 'list' %}">[書籍一覧]</a></li>
29                        </ul>
30                    </div>
31 
32                    <!-- ページタイトル -->
33                    <div id="page_title">
34                        <h2>書籍変更</h2>
35                    </div>
36                </div>
37            </div>
38 
39            <!-- 書籍一覧のコンテンツ部分 -->
40            <div id="main" class="container">
41 
42                <!--  入力フォーム -->
43                <form action="{% url 'update' book.isbn %}" method="POST">
44                    {% csrf_token %}
45                    <table class="detail-table">
46                        <thead>
47                            <tr>
48                              <td></td>
49                              <th>&lt;&lt;変更前情報&gt;&gt;</th>
50                              <th>&lt;&lt;変更後情報&gt;&gt;</th>
51                            </tr>
52                        </thead>
53                        <tbody>
54                            <tr>
55                                <th>ISBN</th>
56                                <td>{{book.isbn}}</td>
57                                <td>{{book.isbn}}</td>
58                            </tr>
59                            <tr>
60                                <th>TITLE</th>
61                                <td>{{book.title}}</td>
62                                <td><input type="text" name="title"></td>
63                            </tr>
64                            <tr>
65                                <th>価格</th>
66                                <td>{{book.price}}</td>
67                                <td><input type="text" name="price"></td>
68                            </tr>
69                        </tbody>
70                      </table>
71                      <input type="hidden" name="isbn" value="{{book.isbn}}">
72                      <input type="submit" value="変更">
73                </form>
74 
75            </div>
76 
77            <!-- フッター部分 -->
78            <footer>
79                <div class="container">
80                    <h4>Copyright&copy; 2018 All Right Reserved.</h4>
81                </div>
82            </footer>
83        </div>
84 
85    </body>
86</html>

43行目から「insert.html」の時と同様、POST送信を行う入力フォームを従えていることがわかります。
また「action=”{% url ‘update’ book.isbn %}”」からフォームを送信(変更をクリック)すると、「http://localhost:8000/bmsdjango/update/」が呼び出されることがわかります。

1<!--  入力フォーム -->
2<form action="{% url 'update' book.isbn %}" method="POST">

「{% url ‘update’ ●●● %}」の「●●●」については、urls.pyの「update/<str:isbn>」における「str:isbn」に該当し、{% url ‘update’ ●●● %}は「http://localhost:8000/bmsdjango/update/●●●」を表します。

■ソースコード
【ファイル名:bmsdjango/urls.py】

1path('update/<str:isbn>', views.update, name='update'),

今回「book」は、Viewから引き継がれたものです。isbn列の値が「http://localhost:8000/bmsdjango/update/●●●」の●●●に合致するBookテーブルの行の各列の値が格納されたBookクラスが格納されているので、book.isbnは「●●●」になります。

そのため「<form action=”{% url ‘update’ book.isbn %}” method=”POST”>」の入力フォームを送信すると、「http://localhost:8000/bmsdjango/update/●●●」へ遷移されます。

図 6.6 7:update.htmlの動き

続いて入力フォームの中身を確認します。
56、57行目における「book.isbn」は、「http://localhost:8000/bmsdjango/update/●●●」における●●●、61行目の「book.title」、「book.price」は、isbn列が●●●の時のtitle列の値、price列の値が格納されます。

図 6.6 8:update.htmlの動き

続いてupdate関数のPOST送信が実行された場合の処理を確認していきます。
「http://localhost:8000/bmsdjango/update」へ遷移されるため、「update.html」にて入力フォームを送信したタイミングが、update関数でPOST送信が実行された場合の処理(54~59行目)が実行されるタイミングです。

図 6.6 9:POST送信後の流れ

では「update関数」のPOST送信が実行された場合の処理(54~59行目)を確認していきましょう。

■ソースコード
【ファイル名:bmsdjango/views.py】

1if (request.method == 'POST'):
2    #POSTデータの値を更新する
3    book.title = request.POST["title"]
4    book.price = request.POST["price"]
5    book.save()
6    #listにリダイレクト
7    return redirect(to='list')

まず55、56行目ではPOST送信のデータを受け取っています。

1book.title = request.POST["title"]
2book.price = request.POST["price"]

図 6.6 10:送信データの受け取り

また受け取ったデータは、変数book(Bookインスタンス)のセッターメソッドtitle、priceを介して、title属性、price属性の値が更新されます。
その上で57行目ではbookを介してsaveメソッドが使用されます。saveメソッドを実行すると、book(Bookインスタンス)の属性値(isbn、title、price)の値を、そのままBookテーブルの各列に紐づけて値が更新されます。

図 6.6 11:POST送信後の流れ

最後、59行目ではredirectメソッドを使用しており、実行により「http://localhost:8000/bmsdjango/list」へリダイレクトされます。

6.6.3 Delete(削除)

続いてDelete処理の流れを確認していきましょう。

urls.py

まずurls.pyを確認すると「http://localhost:8000/bmsdjango/delete」にアクセスすると「delete」に該当する要素として、「delete関数」が実行されることがわかります。

■ソースコード
【ファイル名:bmsdjango/urls.py】

View(view.py)

続いて「http://localhost:8000/bmsdjango/delete」にアクセスした場合に実行されるdelete関数の処理を確認していきましょう。

■ソースコード
【ファイル名:bmsdjango/views.py】

まず36~46行目ではif else文が実行されています。
36行目の「if ‘isbn’ in request.GET:」はHTTPリクエストメソッドが、「GET」かどうかを判定するためのものです。

GET送信が実行された(true)場合、37~44行目が実行されます。trueだった場合の処理の中身を確認すると送信データを受け取っています。

つまりは「http://localhost:8000/bmsdjango/delete?isbn=●●●」に該当する●●●がisbnに格納されます。
続いて40行目を確認するとfilterメソッドが実行されており、引数isbnに●●●が格納されたisbnの値が設定されています。

1if Book.objects.filter(isbn=isbn).exists():

つまりはfilterメソッドの戻り値には、isbn列が●●●の時のBookテーブルのレコードの各列の値が格納されたBookインスタンスが格納されます。

図 6.6 12:filterメソッドの動き

また50行目ではexists()メソッドが実行されています。これはfilterメソッドを介してBookテーブル内に合致するレコードがあるかどうか検索した結果、合致するレコードがあった場合にtrue、なかった場合にfalseが返ってくるメソッドです。

図 6.6 13:existsメソッドの動き

つまりは合致するレコードがあった場合、41~44行目が実行されます。42行目を確認すると「objects.get」メソッドが実行されています。
こちらはfilterメソッドと同様、引数には該当するテーブルの列名(今回のケースではisbn、title、price)を従え、引数に設定した値を検索値としてテーブル内に対象の列に値が存在すれば、該当の行の各列の値を従えたModel(Bookクラス)のインスタンスが生成されます。

1#レコードの取得
2book = Book.objects.get(isbn=isbn)

つまり今回の場合、isbn列の値が、「http://localhost:8000/bmsdjango/delete?isbn=●●●」における●●●の時のBookインスタンスが生成されるということです。

図 6.6 14:objects.getメソッドの処理の流れ

続いて44行目を確認すると変数bookを介してdeleteメソッドが実行されています。

1#レコードの取得
2book.delete()

こちらはBookインスタンスの対応するレコードがテーブルから削除させるためのメソッドです。

図 6.6 15:deleteメソッドの流れ

最後に46行目を確認すると、「http://localhost:8000/bmsdjango/list」へリダイレクトしていることがわかります。

6.6.4 Read(一覧)

最後に一覧処理の流れを確認していきましょう。こちらは「list.html」以外に変更点はありませんので、「list.html」の変更点を説明します。

主な変更点は58~68行目のfor文内の、「64、65行目」です。
【ファイル名:list.html】

64行目のaタグには遷移先のURLとして「http://localhost:8000/bmsdjango/update/●●●」が指定されます(●●●にはisbn列の各値)。
また65行目のaタグには遷移先のURLも同様に「http://localhost:8000/bmsdjango/delete?isbn=●●●」が指定されます。

図 6.6 16:list.html

URLの形を確認すると変更をクリックすると、update関数が実行され、削除をクリックするとdelete関数が実行されることがわかります。


NEXT>> 6.7 本章のまとめ

f