更新機能の付与について
前回はブログ記事を詳細画面(個別ページ)で表示する機能を加えた。
今回は詳細画面から更新ができる機能を加える。
現在のディレクトリ構成は以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
デスクトップ └Blog ├Blog_app │ ├migrations │ ├__init__.py │ ├admin.py │ ├apps.py │ ├models.py │ ├tests.py │ ├views.py │ ├urls.py │ └templates │ └Blog_templates │ ├index.html │ ├create.html │ ├page_list.html │ └detail.html ├db.sqlite3 ├config │ ├・・・ │ └urls.py ├env_blog └manage.py |
更新機能を付与する手順
urls.pyの編集
~デスクトップ/Blog/Blog_app/urls.py
1 2 3 4 5 6 7 8 9 10 11 12 |
from django.urls import path from .views import index, create, page_list, detail, update #[1] app_name = 'Blog_app' urlpatterns = [ path('', index, name='index'), path('index/', index, name='index'), path('create/', create, name='create'), path('page_list/', page_list, name='page_list'), path('detail/<int:pk>/', detail, name="detail"), path('update/<int:pk>/', update, name='update'), #[2] ] |
[1]updateを追記
views.pyのupdate関数をインポートする。
update関数は未作成なので、次の手順で作成する。
[2]path関数を追加
第一引数で指定した内容と一致するURLを利用者がリクエストしてきた場合にこのpath関数が実行される。
具体的には、第二引数で指定するviews.pyのupdate関数を呼び出す。
また、このURLパターンは第三引数でupdateと名付けた。
例として、以下のURLを利用者がリクエストしてきた場合、pk(ID)が1の記事、つまり最初の記事の更新画面が表示される。
views.pyの編集
~デスクトップ/Blog/Blog_app/views.py
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
from django.shortcuts import render, get_object_or_404, redirect #[1] from .models import Blog # Create your views here. def index(request): template_name = "blog_templates/index.html" return render(request, template_name) def create(request): template_name = "blog_templates/create.html" if request.POST: title = request.POST["title"] content = request.POST["content"] object_ = Blog(title=title, content=content) object_.save() return render(request, template_name) def page_list(request): template_name = "blog_templates/page_list.html" pages = Blog.objects.all() context = {'pages': pages} return render(request, template_name, context) def detail(request, pk): template_name = "blog_templates/detail.html" #page = Blog.objects.get(pk=pk) page = get_object_or_404(Blog, pk=pk) context = {'page': page} return render(request, template_name, context) #[2] def update(request, pk): template_name = "blog_templates/update.html" page = get_object_or_404(Blog, pk=pk) #if request.method=='POST': if request.POST: title = request.POST.get('title') content = request.POST.get('content') page.title = title page.content = content page.save() return redirect('Blog_app:detail', pk=pk) context = {'page':page} return render(request, template_name, context) |
[1]redirectを追記
redirectをインポートする。
指定されたURLにリダイレクト(転送)することができる。
ブログ記事の内容を更新した後、詳細画面に転送するために使用する。
指定は以下のように行う。
redirect(‘アプリケーション名’:URL名)
アプリケーション名はurls.pyのapp_nameで指定した名前。
URL名はurls.pyのurlpatterns内にあるpath関数のname属性で記述した内容。
[2]update関数を作成
template_name = “blog_templates/update.html”
変数templates_nameにblog_templatesディレクトリ内のupdate.htmlまでのアドレスを格納。
update.htmlは未作成なので、次の手順で作成する。
page = get_object_or_404(Blog, pk=pk)
変数pageにブログ記事のオブジェクトを格納する。
pkで指定したIDを持つブログ記事がBlogモデルにあればそのタイトル・内容・作成日を変数pageに格納する。ブログ記事がない場合は404エラーを返す
#if request.method==’POST’:
if request.POST:
利用者からのリクエストがPOSTメソッドだった場合に実行する。
POSTメソッドであることを判断する必要がある理由は、update.htmlでPOSTメソッドでフォームを作成しているため。
利用者がブログ記事の内容を書き換え、更新ボタンを押した時にPOSTメソッドでデータが送られる。update関数ではPOSTメソッドであることをここで判断してタイトルや内容を上書きして保存を行う。
title = request.POST.get(‘title’)
content = request.POST.get(‘content’)
変数titleとcontentにPOSTメソッドで送られてきたデータ、つまり利用者が上書きしたブログ記事の内容を保存する。
page.title = title
page.content = content
page.save()
変数pageはBlogモデルを通じてDBから取得してきたオブジェクト。
pageオブジェクトにはtitle, content属性が含まれているので、これを利用者からPOSTメソッドで送られてきた内容で上書きし、最後にsaveを実行する。
return redirect(‘Blog_app:detail’, pk=pk)
ブログ記事の内容を更新した後、redirect関数によって詳細画面へ転送する。
Blog_appはurls.pyでapp_nameに指定したアプリケーション名。
detailはurls.pyのurlspatterns内にあるpath関数でname=detailとなっているものを指定している。
context = {‘page’:page}
return render(request, template_name, context)
変数contextにpageというキーで、変数pageの内容を辞書形式で格納。
update.htmlにcontextを渡しつつ、更新用ページを表示している。
利用者が更新ページにアクセスしたとき、if文の内部ではなくこの部分が最初に実行される。
※明示されていないがGETメソッドを使っている
利用者がデータを更新するためには現在のブログ記事の内容を表示する必要があるため、最初の2行でtemplate_nameと変数pageにモデルを通じてDBから取得したオブジェクトをupdate.html上で表示している。
update.htmlの作成
~デスクトップ/Blog/Blog_app/temlates/blog_templates/update.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 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ブログ</title> </head> <body> <h1>更新</h1> <a href="{% url 'Blog_app:index' %}">トップ</a><br> <a href="{% url 'Blog_app:page_list' %}">一覧</a><br> <form method="POST"> {% csrf_token %} <label for="id_title">タイトル:</label> <input type="text" name="title" id="id_title" value="{{ page.title }}" required><br> <label for="id_content">内容:</label> <textarea name="content" id="id_content" required>{{ page.content }}</textarea><br> <button type="submit">更新</button> </form> </body> </html> |
<h1>更新</h1>
h1タグで見出しとして更新と表示
<a href=”{% url ‘Blog_app:index’ %}”>トップ</a><br>
<a href=”{% url ‘Blog_app:page_list’ %}”>一覧</a><br>
Aタグを使ってトップページと一覧ページへのリンクを作成。
{%%}で囲われた部分でurlテンプレートタグを使ってアプリケーション名がBlog_appであり、path関数のname属性がindexとpage_listとなっている箇所を呼び出す。
brタグは改行。
<form method=”POST”>
POSTメソッドでフォームを作成。
最後に</form>で閉じる。
{% csrf_token %}
{% csrf_token %}はセキュリティ上必要な項目。これがないとエラーになる。POSTメソッドでフォームを作成するときは必ず必要になるので覚えてしまってよい。
<label for=”id_title”>タイトル:</label>
<input type=”text” name=”title” id=”id_title” value=”{{ page.title }}” required><br>
labelタグはページで文字を表示するためのタグ。 利用者が編集はできない。
for=id_titleとしているが、for属性によって何に紐づくラベルなのかを示している。今回はinputタグに紐づけており、このラベルタグで表示されている文字「タイトル:」をクリックすると、inputタグにより作成されたフォームにカーソルが当てられ、すぐに編集ができる。
inputタグは文字を入力するためのタグ。利用者が編集できる。
inputタグにより入力用フィールドが作成され、ここに現在のブログ記事のタイトルが表示される。これを利用者が上書きすることで内容の更新を行う。
inputタグは複数の属性を持つ。ここで言う属性はupdate.html上での属性であり、views.pyやurls.pyでの属性とは別。
type=”text”として、入力フィールドのタイプがテキストであることを明示。
name=”title”として、入力フィールドの名前をつける。
id=id_titleとすることで、labelタグでid=id_titleと一致し、紐づけが完了。
value=”{{ page.title }}”でブログ記事のタイトルを表示する。{{ }}で変数を囲うことでhtmlファイルで変数を扱うことができる。
requiredは、このフィールドが必須入力であることを示す。
<label for=”id_content”>内容:</label>
<textarea name=”content” id=”id_content” required>{{ page.content }}</textarea><br>
labelタグで「内容:」と表示。
id=id_contentとすることで、textareaタグと紐づけている。
textareaタグでブログ記事の内容を表示しつつ、利用者が入力できるフィールドを作成される。
requiredにより必須入力としている。
{{ page.content }}によって内容を表示させる。
<button type=”submit”>更新</button>
</form>
buttonタグはボタンを作成する。
更新というテキストを持つボタンを押すと、利用者が入力した内容をアプリケーション側へ送信し、更新が行われる。
詳細画面(detail.html)からのリンクを作成
~デスクトップ/Blog/Blog_app/temlates/blog_templates/detai.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ブログ</title> </head> <body> <h1>詳細</h1> <a href="{% url 'Blog_app:index' %}">トップ</a><br> <a href="{% url 'Blog_app:page_list' %}">一覧</a><br> {{page.title}}<br> {{page.content}}<br> {{page.created_date}}<br> <a href="{% url 'Blog_app:update' page.id %}">更新</a> <!-- [1] --> </body> </html> |
[1]更新画面へのリンクを作成
Aタグによって更新画面へのリンクを作成。
一覧ページ(page_list.html)からのリンクを作成
~デスクトップ/Blog/Blog_app/temlates/blog_templates/page_list.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 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ブログ</title> </head> <body> <h1>記事一覧</h1> <a href="{% url 'Blog_app:index' %}">トップ</a><br> {% for page in pages %} <ul> <li>{{ page.title }}</li> <li>{{ page.content }}</li> <li>{{ page.created_date }}</li> <li><a href="{% url 'Blog_app:detail' page.id %}">詳細</a></li> <li><a href="{% url 'Blog_app:update' page.id %}">更新</a></li> <!-- [1] --> </ul> {% endfor %} </body> </html> |
[1]
Aタグによって更新ボタンへのリンクを作成
開発用サーバーを起動して確認
開発用サーバーを起動して、画像のように表示されていればOK
開発用サーバーの起動は以下のコマンドで行う。
~デスクトップ/Blog/
1 |
python manage.py runserver |
■一覧画面
■詳細画面
■更新画面
ここで、好きな内容で上書きし、「更新」ボタンを押す。
■詳細画面(更新後)
入力した内容で画面が更新できていればOK
ディレクトリ構成の確認
現在のディレクトリ構成は以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
デスクトップ └Blog ├Blog_app │ ├migrations │ ├__init__.py │ ├admin.py │ ├apps.py │ ├models.py │ ├tests.py │ ├views.py #編集 │ ├urls.py #編集 │ └templates │ └Blog_templates │ ├index.html │ ├create.html │ ├page_list.html #編集 │ ├detail.html #編集 │ └update.html #新規作成 ├db.sqlite3 ├config │ ├・・・ │ └urls.py ├env_blog └manage.py |
urls.pyではviews.pyからupdate関数をインポートし、path関数を追加して新しいURLパターンを作成した。
新しいURLパターンでは、URLの末尾がupdate/pkだった場合にviews.pyのupdate関数を呼び出す。また、このURLパターンはupdateと名付けた。
例:(開発用サーバーを起動した場合)
views.pyではupdate関数を作成した。
update関数が呼ばれた際、利用者からrequestとpkを受け取る。POSTメソッドだった場合はブログ記事のIDがpkと一致するオブジェクトをモデルを通じてDBから取得して、変数titleとcontentに格納してまずはupdate.htmlで表示する。
利用者が内容を上書きして更新ボタンを押すと、if文の内容が実行されてブログ記事の更新を行い、詳細画面へリダイレクトする。
update.htmlでは、タイトルと内容を最初に表示し、編集するための入力フィールドを作成した。
内容を上書きして更新ボタンを押すことで、POSTメソッドでデータをアプリケーションへ送信できる。
page_list.htmlとdetail.htmlではupdate.htmlへのリンクを作成した。
Django記事一覧
前回:【Django】詳細画面を作る(DBから指定したpk,idのデータを1件取得して表示)
コメント