UpdateViewの使い方をマスターしよう

UpdateViewをマスターしようクラスベースビューをマスターしよう

↓↓↓はじめて講座を受ける方はこちら↓↓↓
開発環境を作ろう

ウサギ
ウサギ

前回はCreateVIewを使って日記の詳細表示の方法を勉強したな

今回はUpdateViewを使って、日記の更新画面を作っていくぞ。

完成形の確認

ウサギ
ウサギ

下記が完成した更新画面だ

UpdateViewを使った更新画面

仕様はこんな感じだ。

  • http://127.0.0.1:8000/<日記ID>/ にアクセスすると日記の詳細画面が表示される
  • 詳細画面の編集リンクをクリックすると、http://127.0.0.1:8000/<日記ID>/update/ に遷移し
    更新画面が表示される
  • 投稿にupdated_byを追加する
  • 更新画面は
    • ログイン必須
    • タイトル、本文、カテゴリーの入力フォームが表示される
    • タイトル、本文は入力必須
    • 投稿のupdated_byがログイン中の投稿者に紐つく
    • 作成完了したら、日記の詳細画面に遷移する

UpdateViewを使うとどれだけ分かりやすく、簡単に書けるかやってみるぞ!

ベースアプリの準備

今回は詳細画面が構築されているブランチを使用します!

作業必須。

リポジトリのクローンとベース機能のチェックアウト

ウサギ
ウサギ

まずは詳細画面を表示する機能をあらかじめチェックアウトしておく

$ git clone https://github.com/yheihei/base_diary.git
$ cd base_diary
$ git fetch && git checkout feature/#14

マイグレーションと初期データ投入

ウサギ
ウサギ

次にマイグレーションとloaddataによる初期データの投入だ

$ python manage.py migrate
$ python manage.py loaddata initial.json

この状態でhttp://127.0.0.1:8000/1/を開くと。。。

わいへい
わいへい

よし、日記詳細画面が表示されたね

ログインする場合はhttp://127.0.0.1:8000/admin/に入って行う。

ログインできるユーザー名とパスワードは下記だ。

UserName: yhei
Password: password
日記編集画面

完成版ソースだけ見る場合

ウサギ
ウサギ

今回も完成形を書いたブランチも用意しておいた。

答えだけ先に見たいやつは下記コマンドでブランチをチェックアウトしてくれ

GitHub - yheihei/base_diary at feature/#16
ウサでも分かる中級Django講座の教材. Contribute to yheihei/base_diary development by creating an account on GitHub.
# 完成版ブランチを見たい場合はこちら
$ git fetch && git checkout feature/#16

UpdateViewで機能を作ってみる

基本のフォームを表示する

まずUpdateViewの処理をdiary/views.pyに記述する。

from .models import Post
from django.views.generic.edit import UpdateView


class PostUpdateView(UpdateView):
  model = Post
  fields = ['user', 'title', 'body', 'categories']

UpdateViewを継承したモデルを作成、保存するモデル(Post)をmodel変数に入力する。

また、表示したいフォームをfields変数に入力する。下記のようにだ。

  fields = ['user', 'title', 'body', 'categories']

ここで指定するフォーム名は、Postモデルのカラム名だ。Postモデルを見てみよう。

class Post(models.Model):
  ...
  user = models.ForeignKey(User, on_delete=CASCADE)
  title = models.CharField(max_length=2048)
  body = models.TextField()
  ...
  categories = models.ManyToManyField(
    ...
  )

投稿者のカラムのuser、日記のタイトルと本文を表すtitleとbody、日記のカテゴリを多対多で紐つけるcategoriesを指定すれば、日記の更新ができるな。

次はルーティングの設定だ。

http://127.0.0.1:8000/<日記ID>/update/のアクセスを、UpdateViewにルーティングさせる。

diary/urls.pyに下記を入力する。

from django.urls import path
from . import views
from diary.views import PostDetailView, PostUpdateView

app_name = "diary"
urlpatterns = [
  path("", views.index, name="index"),
  path('<int:pk>/', PostDetailView.as_view(), name='post-detail'),
  # UpdateViewにルーティングさせる
  path('<int:pk>/update/', PostUpdateView.as_view(), name='post-update'),
]

最後に、UpdateViewで表示させるテンプレートを作成する。

UpdateViewのテンプレート名は他のクラスベースビューと同じく自動でデフォルトが決まる。
(指定も可能)

デフォルトは/templates/アプリ名/<modelに指定したクラス名の小文字>_form.htmlだ。

ということで、diary/templates/diary/post_form.htmlに下記を記述する。

{% extends 'diary/base.html' %}
{% block content %}
<article>
  <h2>記事の更新</h2>
  <div class="mt-3">
    <form method="POST">
      {% csrf_token %}
      {% for field in form.visible_fields %}
        <div class="form-group">
          <label>{{ field.label }}</label>
          {{ field }}
          {{ field.errors }}
          {{ field.help_text }}
        </div>
      {% endfor %}
      {% for field in form.hidden_fields %}
        {{ field }}
      {% endfor %}
      <input class="btn btn-primary" type="submit" value="投稿" />
    </form>
  </div>
</article>
{% endblock %}

これでUpdateViewの基本形は完成した。

http://127.0.0.1:8000/1/update/にアクセスしてみると。。。

UpdateViewを使った更新画面
わいへい
わいへい

おお、更新フォームっぽいのができた!

ログイン必須にする

ただ、誰でも日記を更新できてしまうと問題がある。

ログインしているユーザのみこのページを開けるようにするぞ。

ログイン必須にするには、UpdateViewを継承しているクラスに、LoginRequiredMixinクラスを継承してやると良い。

from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy


class PostUpdateView(LoginRequiredMixin, UpdateView):
  # ログインURLも指定する
  login_url = reverse_lazy('admin:login')
  ...

login_url変数に、ログインURLを指定するのも忘れずに。

一旦ログアウトして、http://127.0.0.1:8000/1/update/にアクセスしてみると。。。

UpdateViewをログイン必須にする
わいへい
わいへい

ログインしてないと見られなくなった!

ログインユーザーを投稿更新者(updated_by)として保存する

更新処理完成まであともう少しだ。

今は投稿者を選択するようなUIになっているが、

普通投稿者は変えるべきではないよな?

そこで、

  • 投稿者を変更できないようにし、
  • Postに新たにupdated_by(投稿更新者)を追加
  • そこにログインユーザーを保存する

と言う仕様に変えてみる。

まずは、updated_byを追加する。

diary/models.pyに下記を追加する。

class Post(models.Model):
  ...
  updated_by = models.ForeignKey(
    User,
    default=None,
    on_delete=models.SET_NULL,
    null=True,
    blank=True,
    related_name='updated_posts',
  )

もし投稿者が削除された場合、updated_byNULLになって欲しい。そのため、on_delete=SET_NULLにしておこう。

次にマイグレーションファイルを作り、マイグレートしていく。

$ python manage.py makemigrations
$ python manage.py migrate

次に、

  • Formから投稿者を消し
  • Formの保存時にupdated_byにログインユーザーを紐つけて登録する処理

をやってみる。

こんな感じだ。

class PostUpdateView(LoginRequiredMixin, UpdateView):
  ...
  # fields = ['user', 'title', 'body', 'categories']
  fields = ['title', 'body', 'categories']

  def form_valid(self, form):
    object: Post = form.save(commit=False)
    object.updated_by = self.request.user
    object.save()
    return super().form_valid(form)

form_valid関数はレコードが保存される直前で呼ばれる関数だ。

form_valid関数をオーバーライドし、保存処理のついでにobject.updated_byにログインユーザー(self.request.user)をセットしてやる。

これでupdated_byがきちんと保存される。

保存が完了したら日記詳細画面に遷移させる

また、更新完了後は、日記の詳細画面に遷移して欲しい。

そのためにget_success_url関数をオーバーライドして、遷移先を指定してやる。

class PostUpdateView(LoginRequiredMixin, UpdateView):
  ...
  def get_success_url(self):
    '''
    更新完了したらどこに遷移させるか
    '''
    return reverse('diary:post-detail', kwargs={'pk': self.object.pk})

self.objectには保存したPostモデルが入ってくる。self.object.pkを指定すれば、日記のIDが取得できる。

つまり、どの日記に遷移させるかが指定できたと言うわけ。

ではやってみるぞ。

http://127.0.0.1:8000/1/update/ に遷移して。。。

UpdateViewを使った更新処理
わいへい
わいへい

更新ができた〜〜〜

Formのデザインやバリデーションを変更する方法

Formが多少野暮ったいのでカスタマイズしたいと思うかもしれない。

また変わったバリデーションを行いたい場合もある。

そのやり方はCreateViewの講義でまとめておいた。

気になるヤツは↑を参照してくれ。

まとめ

ウサギ
ウサギ

UpdateViewの使い方をまとめるぞ

  • UpdateViewはModelを指定することで、そのModelに紐ついたレコードを更新画面が作成可能
  • save時に特殊な操作をする場合はform_valid関数が使える
  • get_success_url関数で更新完了後のページを指定する
わいへい
わいへい

CreateViewと結構似てたな

ウサギ
ウサギ

そう、新規作成も更新も基本は同じだな

ウサギ
ウサギ

これでCRUDのCRUができるようになった

ウサギ
ウサギ

残りはD(Delete)だな

ウサギ
ウサギ

簡単なのでサクッと次回のレッスンでやってみるぞ

\ 講座で学んだことを即アウトプットしよう /

次の講座

Djangoの基礎を学びたい方は

Djangoの基礎を固めたい方はこちら(セール時に買うのがおすすめ)

『Djangoパーフェクトマスター』〜インスタ映えを支えるPython超高速開発Webフレームワークを徹底解説!

動画講座で手を動かしながら、ほとんどのことが学べます。

ウサギもここから始めました。

コメント

タイトルとURLをコピーしました