このページでは、Django フレームワークで定義される UpdateView の使い方について説明していきます。
この UpdateView は View というクラスのサブクラスの1つであり、ビューをクラスベースで作成する際に利用するクラスとなります。この View のサブクラス を継承し、さらにクラス変数を定義したりメソッドをオーバーライドすることで、あなたが開発したいアプリに応じたビューを作成することが可能となります。
この辺りのクラスベースビューやクラスベースビューの作り方については下記ページで解説していますので、詳しくはこちらをご参照ください。
また、この UpdateView は、View のサブクラス である CreateView と DetailView と密接に関連しています。というか、この2つのクラスについて理解しておけば UpdateView は簡単に使いこなすことが可能です。これらのクラスについては下記ページで解説していますので、これらのクラスについて理解されていない方は、事前に下記ページを読んでいただくことをオススメします。
Contents
UpdateView
では、UpdateView について解説していきたいと思います。
UpdateView は、名前の通り、データベースに既に保存されているレコードの更新を実現する View のサブクラス となります。
UpdateView は django.views.generic から import して利用します。
from django.views.generic import UpdateView例えば、登録済みのユーザーの情報の更新、投稿済みのコメントの修正といった、データベースに既に登録されているレコードの更新を実現するのが UpdateView となります。
![]()
UpdateView は、『データベースに既に保存されているレコード』を更新することを目的に利用するビューであり、データベースへの新規保存・新規登録に関しては UpdateView ではなく、CreateView によって実現することになります。
UpdateView = CreateView + DetailView
ページの冒頭でも触れましたが、UpdateView は下記ページで紹介している CreateView と DetailView と関係性が深いです。イメージとしては UpdateView = CreateView + DetailView となります。
CreateView の解説ページでも説明していますが、CreateView では GET リクエストを受け取った際にフォームを表示し、さらにフォームからデータが送信されて POST リクエストを受け取った際には、その送信されてきたデータをインスタンス(レコード)としてデータベースのテーブルに新規登録されるようになっています。CreateView はレコードの新規登録を行うビューであるため、表示するフォームの各種フィールドは基本的には空、もしくは、初期値となります。
![]()
これに対し、UpdateView では GET リクエストを受け取った際に、まずデータベースから更新対象となるインスタンス(レコード)の取得が行われます。そして、そのインスタンスの各種フィールドの情報をフィールドにセットした状態のフォームを表示します。これによって、ユーザーが更新前の各種フィールドの情報を確認し、更新すべきフィールドを判断することができるようになります。
![]()
さらに、ユーザーが更新したいフィールドの情報を修正し、ボタンのクリック等でフォームからデータが送信されると POST リクエストがウェブアプリに送信されます。この POST リクエストを UpdateView が受け取った際には、受信したデータをそのままレコードとしてデータベースのテーブルに登録するのではなく、まず最初にデータベースのテーブルからの『更新対象となるインスタンス(レコード)』の取得が行われます。
![]()
そして、そのインスタンスを送信されてきたデータで上書きし、それをデータベースに保存することでインスタンスの更新が実現されることになります。
![]()
このように、CreateView と UpdateView とではリクエストを受け取った時の処理の流れが似ているのですが、『リクエストを受け取った際のデータベースからのインスタンスの取得の有無』が異なります。
CreateView の場合は、リクエストを受け取った際にはデータベースからのインスタンスの取得が行われません。それに対し、UpdateView の場合は、リクエストを受け取った際に、まずデータベースからのインスタンスの取得が行われることになります。
そして、UpdateView がデータベースからのインスタンスの取得を行う際には、DetailView でも定義されている get_object メソッドが実行されることになります。つまり、UpdateView でも DetailView と同じメソッドでデータベースからのインスタンスの取得が行われることになります。
そして、この get_object メソッドでは、特定のテーブルから『プライマリーキー』や『スラッグ』によって特定される1つのインスタンスの取得が行われます。これらのプライマリーキーやスラッグは URL で指定されることになります。また、このインスタンスの取得先のテーブルはクラス変数の model や queryset によって決まります。この辺りに関しても UpdateView と DetailView とで共通となります。
このように、UpdateView は CreateView をリクエスト受け取った際にインスタンスをデータベースから取得するように改造されたもので、そのデータベースからのインスタンスの取得の仕方は DetailView と共通になります。なので、イメージとしては UpdateView = CreateView + DetailView と考えていただいて良いと思います。
スポンサーリンク
UpdateView でのクラスベースビューの作り方
では、次は UpdateView でクラスベースビューを作成する手順について説明していきます。
UpdateView でのクラスベースビューの作り方に関しても CreateView と同様となります。
つまり、views.py に UpdateView を継承するクラスを定義し、そのクラスでクラス変数やメソッドを定義して UpdateView 側で定義されているクラス変数の上書き・メソッドのオーバーライドを行なうことで、ビューを作成していきます。これにより、UpdateView の特徴を活かしながら自身のウェブアプリに応じたビューにカスタマイズしていくことが可能となります。
![]()
また、これも CreateView と同様に、UpdateView ではリクエストに応じて get メソッドや post メソッドが実行されるようになっており、UpdateView のクラス変数や他のメソッドは、これらの get メソッドおよび post メソッドから利用されるようになっています。したがって、UpdateView のサブクラス側でクラス変数やメソッドを上書き・オーバーライドしてやれば、この get メソッドと post メソッドの動作を変化させることができます。
![]()
クラスベースビュー作成時のポイントも CreateView と同様
また、クラスベースビュー作成時のポイントも基本的には CreateView と同様になります。CreateView でクラスベースビューを作成する際には下記の3つがポイントになります。
これらに関しても下記の CreateView の解説ページで説明していますので、詳しくは下記ページを参考にしてください(上記のリンクのジャンプ先も CreateView の解説ページに設定しています)。
データベースからのインスタンスの取得は DetailView と同様
また、UpdateView では CreateView とは異なり、リクエストを受け取った際に、最初にデータベースからインスタンスの取得が行われることになります。このデータベースからのインスタンスの取得は CreateView では行われません。ただし、このインスタンスの取得は DetailView と同じ仕組みで行われ、この際には下記がポイントとなります。
これに関しては下記の DetailView の解説ページで説明していますので、詳細に関しては下記ページを参照してください(上記のリンクのジャンプ先も DetailView の解説ページに設定しています)。
スポンサーリンク
UpdateView のクラス変数
では、次は UpdateView で定義されているクラス変数の紹介を行なっていきます。これらのクラス変数を UpdateView を継承するクラスで定義し直して上書きすることでクラスの動作のカスタマイズを行うことが可能となります。
UpdateView の場合、GET メソッドのリクエストを受け取った際に get メソッドが実行され、GET メソッドのリクエストを受け取った際に post メソッドが実行されることになるため、これらの get メソッドや post メソッドの動作を変化させることを目的にクラス変数の定義を行なっていくことになります。
ただ、ここまでも何回も説明したように、UpdateView は CreateView と DetailView を足し合わせたようなクラスであり、定義されているクラス変数は CreateView と DetailView で紹介したものと同じです(これはメソッドに関しても同じです)。
そのため、このページでは各クラス変数の詳細は解説せず、下記の CreateView と DetailView の解説ページへのリンクのみを示すようにしていきたいと思いますので、その点はご了承ください。
UpdateView のクラス変数の一覧
この UpdateView で定義されるクラス変数には下記のようなものが存在します。
- form_class (
CreateView) - success_url (
CreateView) - fields (
CreateView) - initial (
CreateView) - prefix (
CreateView) - template_name (
CreateView) - template_name_suffix (
CreateView) - model (
DetailView) - queryset (
DetailView) - pk_url_kwarg
DetailView) - slug_url_kwarg (
DetailView) - slug_field (
DetailView) - context_object_name (
DetailView) - extra_context (
ListView) - template_engine (
ListView) - response_class (
ListView) - content_type (
ListView)
各リンクをクリックすれば括弧内に示した View のサブクラス の解説ページにジャンプするようにしています。基本的に、フォームを扱うための設定を行うクラス変数に関しては CreateView の解説ページ、インスタンスを1つのみ取得するための設定を行うクラス変数に関しては DetailView の解説ページ、その他のクラス変数に関しては ListView の解説ページにジャンプするようにしています。
model (or quryset) の定義は必須
ただし、CreateView と異なり、UpdateView ではクラス変数 model の定義が必須となるので注意してください。
CreateView の場合、クラス変数 model は、ビューで扱うフォームクラスを指定する or デフォルトのテンプレートファイルのパスを決定するために定義する必要がありました。ですが、ビューで扱うフォームクラスはクラス変数 form_class の定義で指定することもでき、さらにクラス変数 template_name を定義すればデフォルトのテンプレートファイルのパスが不要となるため、これらを定義する場合はクラス変数 model の定義が不要でした。
なんですが、UpdateView の場合、インスタンスの取得先のテーブルを決定するためにクラス変数 model の定義が必要となります。したがって、クラス変数 form_class とクラス変数 template_name を定義したとしても、クラス変数 model の定義も別途必要となります。
model の代わりにクラス変数 queryset を定義しても良いです
このように、インスタンスの取得先のテーブルを指定するためのクラス変数の定義が必須となる点が、CreateView とは異なるので注意してください。
ちなみに、form_class を定義し、model (と queryset) を定義しなかった場合、ビューが動作する際に下記のような例外が発生することになります(CommentUpdate 部分は UpdateView のサブクラスの名称によって変わります)。
CommentUpdate is missing a QuerySet. Define CommentUpdate.model, CommentUpdate.queryset, or override CommentUpdate.get_queryset().
UpdateView のメソッド
次に UpdateView の持つメソッドを紹介していきます。UpdateView を継承したクラスを定義し、そのクラスで UpdateView の持つメソッドをオーバーライドしてやることで UpdateView とは異なる動作のクラスを実現することができるようになります。
スポンサーリンク
UpdateView のメソッド一覧
UpdateView の持つメソッドの一覧は下記のようになります。あくまでもクラスのカスタマイズ目的でオーバーライドを行う可能性のあるものを挙げており、as_view などのカスタマイズは行わないであろうメソッドは省略しています。
また、UpdateView は get メソッドと post メソッドを持っており、メソッドが GET のリクエストを受け取った場合は get が実行され、メソッドが POST のリクエストを受け取った場合は post が実行されようになっています。そして、これらの get や post の中から各種メソッドが実行されるようになっています。
get:リクエストのメソッドがGETの場合の処理を実行するpost:リクエストのメソッドがPOSTの場合の処理を実行するget_context_data:テンプレートに渡すコンテキストを生成するget_form:フォームクラスのインスタンスを取得するget_form_class:フォームクラスを取得するget_form_kwargs:フォームクラスのコンストラクタに指定するパラメータを取得するget_initial:initialへの指定値を取得するget_prefix:prefixへの指定値を取得するform_valid:フォームから送信されてきたデータでデータベースに保存されているレコード・インスタンスを更新し、特定の URL へのリダイレクトレスポンスを返却する(妥当性の検証が OK の時に実行される)form_invalid:再度フォームを表示する(妥当性の検証が NG の時に実行される)get_success_url:リダイレクト先の URL を取得するget_template_names:テンプレートファイルの名前を取得するrender_to_response:レスポンスを返却するget_context_object_name:context_object_nameへの指定値を取得するget_queryset:インスタンスの集合(クエリセット)を取得するget_object:インスタンスを取得するget_slug_field:slug_fieldを取得する
get メソッドと post メソッドの簡単な処理の流れは CreateView の解説ページの get メソッドの処理の流れ と post メソッドの処理の流れ でそれぞれ説明していますので、これらのメソッドの処理の流れを知りたい方はリンクをクリックして解説箇所にジャンプしていただければと思います。ただし、これらのリンク先で説明しているのはあくまでも CreateView の場合の処理であって、UpdateView の場合は get メソッドや post メソッドが実行された際に更新対象のインスタンスが取得されるようになっています。
そして、ここで取得された更新対象のインスタンスがフォームクラスのコンストラクタに引数として指定されることで、更新対象のインスタンスがセットされた状態のフォームが生成され、それによって更新対象のインスタンスの情報がセットされたフォームが表示されたり、インスタンス(レコード)の更新処理が実現されるようになっていたりします。
また、特にオーバーライドする機会の多いメソッドは、これも CreateView 同様に form_valid と get_success_url になると思います。このオーバーライドに関しても下記の CreateView の解説ページの CreateView のメソッド で説明していますので、詳細に関しては下記ページを参照していただければと思います。
UpdateView が生成するコンテキスト
続いて UpdateView が生成するコンテキストについて説明しておきます。
これに関しても CreateView + DetailView という考え方で良くて、UpdateView が生成するコンテキストには下記の要素が含まれます。
'object': データベースから取得されたインスタンスcontext_object_name: データベースから取得されたインスタンス'form': フォームクラスのインスタンス
context_object_name に関しては、DetailView の解説ページの context_object_name で説明したように、クラス変数の定義で変更することも可能です。また、デフォルトは モデルクラス名 (小文字) となっています。モデルクラス名が Comment であれば 'comment' となります。
上記以外のデータをコンテキストにセットしてテンプレートファイルから参照できるようにしたい場合は、ListView の解説ページの extra_context で説明しているクラス変数 extra_context を定義したり、get_context_data のオーバーライドを行なったりしてコンテキストの要素を追加する必要があります。
UpdateView の利用例
最後に、ここまでの説明のまとめとして、UpdateView を継承するクラスでのビューの作成例を示していきたいと思います。
プロジェクトとアプリの作成やモデルの定義・マイグレーションの手順に関しては下記ページの ListView の利用例 と同じとなりますので、ここでは説明を省略させていただきます。ListView の解説ページの利用例を読んでいない方は、下記ページの プロジェクトとアプリの作成 と モデルの作成とマイグレーション を読んで手順を進めていただければと思います。
スポンサーリンク
フォームの定義
プロジェクトやアプリ、モデルの準備が済んだ後は、CreateView の時同様にフォームクラスの定義を行ないます。
まず、forum フォルダの下に forms.py というファイルを新規作成し、その forms.py の中身を下記のように変更して保存してください。
from django import forms
from .models import Comment
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['text', 'slug']クラスベースビューの作成
続いて、本題のクラスベースビューの作成を行っていきます。今回は、ここまでの説明の通り UpdateView を継承するクラスを定義し、そのクラスを、クラス変数の定義とメソッドのオーバーライドによってカスタマイズしていきます。
今回は、下記のように views.py を変更することでクラスベースビューを作成したいと思います。
from django.views.generic import DetailView, CreateView, UpdateView
from .models import Comment
from .forms import CommentForm
from django.urls import reverse
class CommentUpdate(UpdateView):
model = Comment
form_class = CommentForm
pk_url_kwarg = 'comment_id'
template_name = 'forum/commentupdate.html'
def get_success_url(self):
return reverse('comment', kwargs={'comment_id':self.object.id})
class CommentCreate(CreateView):
form_class = CommentForm
template_name = 'forum/commentcreate.html'
def get_success_url(self):
return reverse('comment', kwargs={'comment_id':self.object.id})
class CommentDetail(DetailView):
model = Comment
pk_url_kwarg = 'comment_id'
template_name_suffix = 'info'この views.py においては3つのクラスを定義しており、1つ目は DetailView のサブクラスの CommentDetail となります。このクラスは、CommentCreate や CommentUpdate の post メソッドが実行された際のリダイレクト先として利用するために定義しています。
2つ目は CreateView のサブクラスの CommentCreate になります。インスタンスの更新を行うためには事前にインスタンスをデータベースのテーブルに新規登録しておく必要がありますので、このクラスを利用してデータベースにインスタンスを新規登録し、そのインスタンスを CommentUpdate で更新を行うようにしていきます。
そして、3つ目が、このページで解説している UpdateView のサブクラスである CommentUpdate となります。UpdateView のサブクラスの場合は、クラス変数 form_class だけでなくクラス変数 model の定義も必要である点に注意してください。
CommentUpdate のクラス変数 form_class には、先ほど forms.py に定義した CommentForm を指定しています。この CommentForm は CommentCreate でもクラス変数 form_class に指定されていますが、別にこれらのクラスで必ず同じフォームクラスを利用する必要があるというわけではないです。新規登録時と更新時とでユーザーからの入力受付を行いたいフィールドが異なるのであれば、別のフォームクラスを指定してやるのでも良いです。
別々のフォームクラスを指定する場合でも、インスタンスの保存先のテーブルは新規登録時と更新時とで同一のものになるようにする必要があるので注意してください
例えば、モデルフォームクラスを利用するのであれば、そのモデルフォームクラスの model 属性に同じモデルクラスを指定するようにする必要があります
また、CommentUpdate ではクラス変数 pk_url_kwarg の定義も行っていますが、この意味合いについては下記ページの pk_url_kwarg の節で解説していますので、詳しくは pk_url_kwarg を参照していただければと思います。
また、CommentCreate と同様に CommentUpdate でも get_success_url をオーバーライドし、インスタンスの更新後に、そのインスタンスの詳細ページ(CommentDetail で表示されるページ)を表示するようにしています。この get_success_url のオーバーライドは、下記ページの CreateView の利用例 で示したものと全く同じなので、詳細に関しては CreateView の利用例 を参照していただければと思います。
ビューと URL とのマッピング
次は views.py で定義したビューと URL とのマッピングを行なっていきます。
まず、classviewproject フォルダの下にある urls.py を下記のように変更してください。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('forum/', include('forum.urls')),
]続いて、forum フォルダの下に urls.py を新規作成し、中身を下記のように変更してください。
from django.urls import path
from . import views
urlpatterns = [
path('update/<int:comment_id>/', views.CommentUpdate.as_view(), name='update'),
path('create/', views.CommentCreate.as_view(), name='create'),
path('comment/<int:comment_id>/', views.CommentDetail.as_view(), name='comment'),
]このように各種 urls.py を作成しておくことで、ルートパス指定で /forum/update/<int:comment_id>/ へのリクエストがあった際に CommentUpdate が動作するようになります。この <int:comment_id> 部分には、更新対象となるインスタンスに割り当てられたプライマリーキーを指定する必要があります。そして、ここで指定されたプライマリーキーが割り当てられているインスタンスがデータベースから取得され、その後は CreateView と同様の動作でフォームの表示やデータベースへのインスタンスの保存(更新)が行われることになります。
また、ルートパス指定で /forum/create/ へのリクエストを送信することで CommentCreate が動作してインスタンスの新規登録を行うことも可能です。インスタンスの更新を行うためには、事前にインスタンスの新規登録を行っておく必要があります。
スポンサーリンク
テンプレートの作成
次はテンプレートファイルを作成します。ソースコードの変更としては、これが最後となります。
CommentUpdate が利用するテンプレートファイル
CommentUpdate ではクラス変数 template_name を定義し、template_name には 'forum/commentupdate.html' を指定しているため、CommentUpdate では “アプリ内の templates フォルダから見た相対パス” が 'forum/commentupdate.html' となるテンプレートファイルが利用されることになります。したがって、このパスにテンプレートファイルを用意しておく必要があります。
そのため、まずは forum フォルダの中に templates フォルダを作成し、さらに templates の中に forum フォルダを作成してください。さらに、最後に作成した forum フォルダの中に commentupdate.html を新規作成し、中身を下記のように変更して保存してください。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Example of UpdateView</title>
</head>
<body>
<main>
<h2>コメントの修正</h2>
<form action="{% url 'update' object.id %}" method="post">
{% csrf_token %}
<table>{{ form.as_table }}</table>
<p><input type="submit" value="送信"></p>
</form>
</main>
</body>
</html>このテンプレートファイルでは変数として form と object を参照しています。で、UpdateView が生成するコンテキストで説明したように、UpdateView で生成されるコンテキストには 'form' キーとしてフォームクラスのインスタンスがセットされており、テンプレートファイルに {{ form.as_table }} と記述しておくことで、そのフォームクラスに定義されているフィールドがテーブル形式で HTML に埋め込まれることになります。そして、それがページとして表示されることで、それらの入力フィールドを含むフォームが表示されることになります。
また、フォームで 送信 ボタンがクリックされた際には、下記の行によって urls.py で 'update' と名前を付けられた URL に object.id (プライマリーキー)がセットされた URL への POST リクエストが送信されることになります。この URL はルートパス形式で /forum/update/{object.id}/ となり、このリクエストを受け取ることで、CommentUpdate が動作してデータベースに保存されているインスタンスの更新が行われることになります。
<form action="{% url 'update' object.id %}" method="post">このように、DetailView 同様に、UpdateView のサブクラスが動作する際にはデータベースから取得するインスタンスを1つに特定するための情報が URL にセットされている必要があるという点がポイントになります。そして、それを実現できるように urls.py やテンプレートファイルを実装する必要がある点が、UpdateView を使いこなす際のポイントになると思います。
CommentCreate が利用するテンプレートファイル
他のテンプレートファイルに関してはサラッと説明していきたいと思います。
まず、CommentCreate で利用されるテンプレートファイルに関しては、先ほど最後に作成した forum フォルダの下に commentcreate.html を新規作成し、中身を下記のように変更して保存してやることで準備完了となります。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Example of CreateView</title>
</head>
<body>
<main>
<h2>コメントの投稿</h2>
<form action="{% url 'create' %}" method="post">
{% csrf_token %}
<table>{{ form.as_table }}</table>
<p><input type="submit" value="送信"></p>
</form>
</main>
</body>
</html>CommentDetail が利用するテンプレートファイル
続いて、CommentCreate で利用されるテンプレートファイルに関しては、先ほどと同様に forum フォルダの下に commentinfo.html を新規作成し、中身を下記のように変更して保存してやることで準備完了となります。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Example of DetailView</title>
</head>
<body>
<main>
<h2>コメント({{ comment.id }})</h2>
<table>
<tbody>
<tr><td>ID :</td><td>{{ comment.id }}</td></tr>
<tr><td>TEXT :</td><td>{{ comment.text }}</td></tr>
<tr><td>DATE :</td><td>{{ comment.date }}</td></tr>
<tr><td>SLUG :</td><td>{{ comment.slug }}</td></tr>
</tbody>
</table>
</main>
</body>
</html>以上でテンプレートファイルの準備は完了となります。
動作確認
最後に動作確認を行なっておきましょう!
まずは、manage.py が存在するフォルダで下記コマンドを実行します。
% python manage.py runserver
これにより、開発用ウェブサーバーが起動しますので、ウェブブラウザから作成したアプリのページを表示することが可能となります。
次に下記 URL をウェブブラウザで表示してみてください。
http://localhost:8000/forum/create/
この URL をウェブブラウザで表示すれば下図のような text と slug の入力フィールドを持つフォームが表示されるはずです。これは CommentCreate によって表示されるフォームとなります。
![]()
表示されたフォームで適当な半角英数字の文字列を text と slug に入力して 送信 ボタンを押せば、これらのフィールドに入力されたデータが対応するフィールドにセットされ、さらに id(プライマリーキー) と date(新規作成された日時) が自動的にセットされた Comment のインスタンスがデータベースに新規登録されることになります。ただし、slug に関してはデータベースに保存されている他の Comment のインスタンスと重複していると妥当性の検証結果が NG になるようになっているので注意してください。
送信 ボタンを押してインスタンスがデータベースに新規登録されれば、リダイレクトが行われ、そのインスタンスの詳細ページに自動的に遷移するようになっているはずです。ここまでは CommentCreate の解説ページでの動作確認結果と同じです。
![]()
続いて、下記の URL をウェブブラウザで開いてください。ただし、下記における URL の最後の 1 の部分は、先ほど新規登録したインスタンスの ID に合わせて変更するようにしてください。
http://localhost:8000/forum/update/1/
そうすれば、次は下図のようなフォームが表示されると思います。ポイントは、text フィールドと slug フィールドに、URL の最後部分で指定した ID を持つインスタンスのもの、つまり更新対象のインスタンスのフィールドにセットされている情報が表示されるという点になります。UpdateView のサブクラスの場合、こういった更新対象のインスタンスの情報がセットされた状態でフォームが表示されることになります。
![]()
さらに、このフォームで text フィールドと slug フィールドの値を変更したのちに 送信 ボタンをクリックしてみてください。インスタンスの新規登録時と同様にリダイレクトが行われ、コメントの詳細ページが表示されることになると思いますが、先ほど変更した値に応じて、表示される各種フィールドの値も変化していることが確認できると思います。また、ID は先ほど新規登録時に割り振られたものから変化していないため、新規登録したインスタンスそのものの更新が行われていることが確認できると思います。
![]()
CreateView の場合は、データベースへのインスタンスの保存を行うたびに新たな別のインスタンスとして新規登録されることになります。そして、新たに保存されたインスタンスには異なるプライマリーキーが割り振られることになります。それに対し、UpdateView の場合は、データベースに保存されているインスタンスを上書きする形で保存されることになります。こういった違いも、この結果から確認していただけるのではないかと思います。
まとめ
このページでは、UpdateView および UpdateView を継承したクラスベースビューの作り方について解説しました!
UpdateView はデータベースに既に保存されているインスタンス(レコード)を更新するための View のサブクラス であり、このクラスを継承することで、登録済みのユーザーの情報更新や投稿済みのコメントの修正等を行うページを簡単に実現できます。
解説の中で何回も説明しましたが、UpdateView はイメージとしては “CreateView + DetailView” であり、定義されているクラス変数やメソッドもこれらを足し合わせたものになっています。そのため、UpdateView を理解するためには、まず CreateView と DetailView について理解していただくのが良いと思います。これらが理解できれば UpdateView も使いこなせるようになると思います。
ちょっと解説が CreateView と DetailView の解説ページへのリンクばかりで分かりにくかったかもしれませんが、まずは CreateView と DetailView の解説ページを読んで UpdateView への理解を深めていただければと思います!
このサイトでは他の View のサブクラス についても説明していますので、他のページも是非読んでみてください!

