Djangoのユーザ管理アプリ作成の目次ページはこちらです。
今回は、フォーム機能を使ってDBへ新規登録をさせます。
UdemyのDjangoの基礎をマスターして、3つのアプリを作ろう!を参考に勉強していています。
また、フォームを扱っていくのでHTMLの基本的な知識がある方でないとも難しいかもしれません。
更新処理の流れ
登録の時と同じで、以下の流れです。
①入力フォームをリクエストから呼び出す
②入力フォームをブラウザに表させる
③フォームに入力したデータをサーバに渡して更新
④更新した結果をブラウザに表示
この順番で処理を作成していきます。
①入力フォームをリクエストから呼び出す(urls.py)
まず最初に「~users/edit/id」と言うURLをユーザー更新のURLにします。
そのために、URLへアクセスされたときの動作をアプリのurls.pyに記入します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
from django.urls import path from . import views #import views urlpatterns = [ path('', views.showUsers, name='showUsers'), #ユーザの詳細情報を表示する処理を呼び出す path('<int:id>', views.showDetail, name='showDetail'), #ユーザの登録フォームを呼び出す path('create', views.showCreateUserForm, name='showCreateUserForm'), #ユーザ登録する処理を呼び出す path('add', views.addUser, name='addUser'), #ユーザ編集するフォームを呼び出す path('<int:id>/edit', views.showEditUserForm, name='showEditUserForm'), ] |
15行目に追記をしました。
※この次にviews.pyの説明を記載します。
一旦viewsのことは置いておいて、やっていることだけ理解してみて下さい。
path(‘<int:id>/edit’, views.showEditUserForm, name=’showEditUserForm’),の解説です。
‘<int:id>/edit’:URLがusers/id/edit/場合の指定した処理を呼ぶという意味
views.showEditUserForm:views.pyのshowEditUserFormの処理を呼ぶという意味です。
name=’showEditUserForm’:リンク先に指定するときの名前で後で使います。
②編集フォームをブラウザに表させる
新規登録フォームは入力欄は空白でしたが、
編集フォームではユーザの情報をフォームに表示させます。
そのため、
以下の流れになります。
①更新対象のユーザ情報を取得
②htmlへフォームを渡す
③ブラウザにフォームを表示させる
※フォームは前回新規登録の時に作成したものを使います。
ブラウザに編集フォームを表示させる(views.py)
①~③はすべてviews.pyで作ります。
以下を追記しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# 編集フォームをHTMLへ返す def showEditUserForm(request,id): #idをもとにユーザ情報を取得 userinfo = get_object_or_404(UserInfo,pk=id) #フォームをオブジェクトを作成 userForm = UserForm(instance=userinfo) #ユーザ情報をフォームに格納 context = { 'userinfo':userinfo, 'userForm':userForm, } #user.htmlへデータを渡す return render(request, 'myapp/edit.html',context) |
5行目で更新対象のユーザ情報を取得しています。
7行目ではフォームをインスタンス化して、
16行目でHTML側に情報を渡しています。
ユーザ情報は更新した後に、対象のユーザページを表示するために渡しています。
フォームを表示するHTML作成(edit.html)
edit.htmlはまだ作っていないので、以下に作成します。
C:\django\myproject\myapp\templates\myapp
htmlの中身は以下です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{% extends './base.html' %} {% load bootstrap4 %} {% block app %} <h1>ユーザ編集</h1> <form action='{% url "showUsers" %}' method='post' class='form'> <!-- ユーザー編集フォームを表示 --> {% csrf_token %} {% bootstrap_form userForm %} <button type='submit' class='btn btn-outline-primary'>更新</button> <a href='{% url "showUsers" %}' class='btn btn-outline-secondary'>戻る</a> </form> {% endblock %} |
ほとんどcreate.htmlのコピペです。
ボタンクリック時のactionで呼び出す関数を変えるだけです。
※ユーザを更新する処理はこの次に書きます。
今はエラー回避のためにユーザ一覧へ遷移するようにしています。
表示させてみるとこんな形で、idをもとにユーザ情報を表示できています。
③フォームに入力したデータを登録後、結果表示
現状は更新ボタンクリック時にユーザ一覧を表示していますが、ユーザ一情報を更新する処理を呼ぶようにします。
まずは更新ボタンをクリックした後、DBに登録する処理を作っていきます。
更新処理を呼び出す(urls.py)
まずはurls.pyにユーザを更新する処理を呼ぶように記載します。
1 2 |
#ユーザ更新する処理を呼び出す path('<int:id>/update', views.updateUser, name='updateUser'), |
この処理をアプリのurls.pyに追記します。
編集フォームの時と同じで、
<int:id>/updateのURLであれば、viewsのupdateUserを呼び出すという意味です。
updateUserの処理は次で作成します。
ユーザ情報DBに更新する処理を作成(views.py)
処理の流れとしては、以下になります。
①フォームデータをDBに更新
②ユーザ詳細ページを表示
以下の処理を追加して①②両方ともviews.pyに記載しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#~~~~~~~~~~~~~~~~~ # フォームから受取ったデータをDBに更新する def updateUser(request,id): #リクエストがPOSTの場合 if request.method == 'POST': #idからユーザデータを取得 userInfo = get_object_or_404(UserInfo,pk=id) #ユーザ情報と、リクエストをもとにフォームをインスタンス化 userForm = UserForm(request.POST,instance=userInfo) if userForm.is_valid(): userForm.save() #更新後、対象ユーザの情報を表示 userInfo = get_object_or_404(UserInfo,pk=id) context = { 'userinfoDetail': userInfo, } #detail.htmlへデータを渡す return render(request, 'myapp/detail.html',context) |
9行目について
userFormに変数にPOSTで受取った情報と、対象ユーザーの情報を入れています。
11行目のuserForm.save()
登録の時と同じsave()を使っています。
なぜ全く同じメソッドを呼んで、登録と更新が勝手に分かれるのか調べてみたところ、djangoの仕様で以下になっているそうです。
既にプライマリキーがあるデータの条件を指定した場合は、INSERTでなく
UPDATE SQL 文が実行されます。Django SQL データベース INSERT UPDATE 追加更新方法 save() create() add() update()
userFormの引数になっているuserInfoはPKが入っているので、自動的に更新になります。
デバッグ実行で止めて、userForm → instanceとたどっていくと、確かにプライマリキー(pk)がありました。
14行目~20行目で、更新した後のユーザ情報を取得して、詳細ページに表示させています。
更新ボタンクリック後にupdateUserを呼ぶ(edit.html)
これでユーザ更新する処理が作成できました。
最後に、edit.htmlの更新ボタンクリックした後の処理を書き換えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{% extends './base.html' %} {% load bootstrap4 %} {% block app %} <h1>ユーザ編集</h1> <form action='{% url "updateUser" userinfo.id %}' method='post' class='form'> <!-- ユーザー編集フォームを表示 --> {% csrf_token %} {% bootstrap_form userForm %} <button type='submit' class='btn btn-outline-primary'>更新</button> <a href='{% url "showUsers" %}' class='btn btn-outline-secondary'>戻る</a> </form> {% endblock %} |
7行目の{% url “showUsers” %}を
{% url “updateUser” userinfo.id %}に書き換えました。
これで、ユーザー詳細ページに遷移できます。
編集フォームを呼び出すshowEditUserFormで、userinfoをHTMLへ渡していたのは、
ユーザ情報のidを遷移先のURLにするためです。
localhost:8000/users/1/editにアクセスして、
事項紹介のサッカーを野球にして更新ボタンを押してみると。
更新されて、「サッカー」が「野球」に変わりました!
ユーザ編集ボタンをユーザ一覧に作成(users.html)
最後に、このままだとユーザ編集画面に行くことができません。
なのでユーザ一覧画面に、編集ボタンを作っておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
{% extends './base.html' %} {% block app %} <h1>ようこそ!</h1> <!-- テーブル --> <table class="table table-striped table table-bordered "> <thead> <tr> <th colspan="3">{{msg}}:{{count}}名</th> </tr> </thead> <tbody align="center"> <!-- count件(行)数分をループ --> {% for user in userinfo %} <tr> <!-- 4列分ユーザ情報を出力 --> <td>{{user.userName}}</td> <td><a href="{% url 'showDetail' user.id %}" class="btn btn-outline-primary">詳細</a> </td> <!-- 編集ボタン --> <td><a href="{% url 'showEditUserForm' user.id %}" class="btn btn-outline-primary">編集</a> </td> </tr> {% endfor %} </tbody> </table> <a href="{% url 'showCreateUserForm' %}" class='btn btn-outline-primary'>ユーザ追加</a> {% endblock %} |
20行目でユーザ編集ボタンを追加しました。
引数にはユーザ情報のidをセットしています。
これで編集ボタンが追加できました。
(おまけ)ModelFormに複数行入力のテキストエリアを表示(forms.py)
よく見てみると、自己紹介は500文字まで入力可能なのに、改行をすることができませんでした…
テキストボックスではなく、テキストエリアに変えてあげればOKです。
forms.pyを以下のように修正しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
from django import forms from . models import UserInfo class UserForm(forms.ModelForm): class Meta: model = UserInfo fields = ('userName', 'country','sex','address','selfIntroduction') labels={ 'userName':'名前', 'country':'出身国', 'address':'住所', 'sex':'性別', 'selfIntroduction':'自己紹介', } #自己紹介をテキストエリアにする widgets = { 'selfIntroduction': forms.Textarea(attrs={'rows':4, 'cols':30}), } |
17行目の記述方法でテキストエリアに変えることができます。
今回はここまでです!