Djangoでモデルを更新・編集する方法
約474日前
2021年4月25日15:59
デジタル
Django
![]()
2021/4/25 投稿
Djangoを使った開発中に覚えたことを備忘録として残します。
今回は作成済みのモデルをウェブページ上で更新・編集する方法を解説します。
ウェブページ上でモデルを更新・編集する。
まずこれから実施する更新・編集のイメージを共有します。
![]()
Todoアプリを作るとき、個別のタスクに下記のような5つの状況ステータスを設けると仮定します。
未着手、実施中、完了、保留、中止
models.pyではこのように定義します。
5つのステータスは予めDjangoのadminページで作っておきます。
![]()
作成済みのタスクのステータスを変更する場合を考えましょう。
例えば「未着手」状態のタスクを開始し、「実施中」のステータスに変更する場合や、
もしくは「実施中」だったタスクが終わったので、「完了」ステータスに変更する場合があります。
![]()
このように
作成済みのモデルのパラメーターを変更する方法を次項で解説します。
上記のタスク管理イメージが「ワンクリック変更」に該当します。
![]()
「着手」ボタンを押せば、そのタスクのステータスが「未着手」→「実施中」に変わります。
html上の着手ボタンは下記のように記述し、ボタンが押されたタスクのidを参照し、専用のページに移動するようにします。
次にviews.pyに実行するビューを作成します。
このビューが実行されるとき、一緒に「pk」という変数が渡されています。
「task.id」は書き換え対象タスクのID(識別番号のようなもの)です。
この「task.id」が入ったurlがクリックされたことで、urls.pyの'start/<int:pk>'の<int:pk>部分がtask.idに置き換わります。
このpk = task.idという情報を持ったままviews.pyのStartビューが実行されます。
つまり
ビューの続きを見ていきましょう。
まず書き換え対象のモデルを変数「task」に格納します。
こうすることで着手ボタンが押されたタスクと同じタスクモデルをビュー内に呼び出すことができます。
続いて「実行中」ステータスを割り当てます。
「task.status」はStatusモデルから選択する形式ですので「task.status = "Ongoing"」という割り当て方はできません。
これはmodels.pyを見たら分かります。
上記の理由の為、「new_status」というStatusモデル(status="Ongoing")を用意する必要があるのです。
このStatusモデルをTask.statusに割り当てます。
書き換えた後はsave()メソッドでモデルを上書き保存します。
モデルの更新が終わったので、元のトップページにリダイレクトします。
これでワンクリック変更が完了です。
![]()
上記のタスク管理の中に歯車アイコンがありますね。
ここを押すと該当タスクの詳細を変更することができます。
![]()
上記の例ではタスクの優先度パラメータを「最優先(Urgent」から「低い(Low)」に変更しています。
この編集方法を解説します。
html上の歯車ボタンは下記のように記述し、アイコンが押されたタスクのidを参照し、編集ページに移動するようにします。
Font Awesomeについては別途記事を書こうと思います。ここでは便利なアイコンライブラリと思っておけば大丈夫です。
まだurls.pyに上記ページの設定を作っていないので、作ります。
次にviews.pyに実行するビューを作成します。
まず「if request.method == "POST":」の部分は飛ばして「else:」文を見ましょう。
この編集ページを開くときはGETメソッドで開かれるので、「if request.method == "POST":」は実行されず「else:」が実行されます。
ついでに「instance=task」となっていますね。
AddTaskFormはタスクを追加するときに使用するフォームのことです。
forms.pyで定義しています。
「instance=task」としたことで、このフォーム入力画面には既に登録済みのパラメータが入力された状態で表示されるようになります。
新規追加画面の場合は何もフォームには入っていません。
![]()
編集画面ではフォームに元々のデータが入った状態で表示されます。
![]()
ビューの続きを見ましょう。
task_edit.htmlの中身を確認します。
for文で書けばもっとスッキリしますが、こちらもあえて(略)です。
instance=taskとしたので、ここで表示している3項目のフォーム
「form.task」
「form.priority」
「form.status」
には既にtaskに登録済みのパラメータが入力された状態で表示されます。
さて、それでは編集を行いましょう。
編集画面の「優先度」フォームは「最優先(Urgent)」となっていますので、「低い(Low)」にします。
![]()
その後、「変更する」ボタンを押します。
「変更する」ボタンはhtml上ではこのように書かれています。
フォームが送信(=POST)されると、views.pyで先ほど説明を飛ばした「if request.method == "POST":」の部分が実行されます。
ここで重要なのが第二引数の「instance=task」の部分です。
この引数が無いとDjangoは送信されたデータが新しいTaskモデルだと認識するので、新規タスクの追加になってしまいます。
当初の目的はタスクの編集(=上書き)ですので、上書きする対象を第二引数で指定します。
その後、通常通りフォームの入力内容にミスが無ければタスクの保存処理に移ります。
上書き保存が完了した後、元のトップページにリダイレクトします。
これで編集作業が完了となります。
以上、2通りのモデル変更方法を解説しました。
実際に自分でいじってみると理解が深まると思いますので、失敗しながらトライしてみて下さい。
お疲れ様でした。
デジタル
Django
改訂履歴
2021/4/25 投稿
1. 背景
Djangoを使った開発中に覚えたことを備忘録として残します。
今回は作成済みのモデルをウェブページ上で更新・編集する方法を解説します。
2. ゴール
ウェブページ上でモデルを更新・編集する。
3. はじめに
まずこれから実施する更新・編集のイメージを共有します。
Todoアプリを作るとき、個別のタスクに下記のような5つの状況ステータスを設けると仮定します。
未着手、実施中、完了、保留、中止
models.pyではこのように定義します。
models.pyステータスというモデルを作成しておき、タスクモデルでステータスの中からForeignKeyで1つ選択します。
class Status(models.Model):
"""Status list"""
status = models.CharField(verbose_name='状況', max_length=10, blank=True, null=True)
def __str__(self):
return self.status
class Task(models.Model):
"""Task info"""
task = models.CharField(verbose_name='やること', max_length=255, blank=True, null=True)
status = models.ForeignKey(
Status, verbose_name='状況', on_delete=models.PROTECT)
def __str__(self):
return self.task
5つのステータスは予めDjangoのadminページで作っておきます。
作成済みのタスクのステータスを変更する場合を考えましょう。
例えば「未着手」状態のタスクを開始し、「実施中」のステータスに変更する場合や、
もしくは「実施中」だったタスクが終わったので、「完了」ステータスに変更する場合があります。
このように
作成済みのモデルのパラメーターを変更する方法を次項で解説します。
4. モデルの更新・編集
4.1 - ワンクリック変更
上記のタスク管理イメージが「ワンクリック変更」に該当します。
「着手」ボタンを押せば、そのタスクのステータスが「未着手」→「実施中」に変わります。
html上の着手ボタンは下記のように記述し、ボタンが押されたタスクのidを参照し、専用のページに移動するようにします。
htmlまだurls.pyに上記ページの設定を作っていないので、作ります。
<a class="btn btn-outline-success" href="/taskapp/start/{{task.id}}" role="button">
着手
</a>
urls.pyこれでボタンが押されたときに「Start」というビューが実行される準備ができました。
urlpatterns = [
path('', views.TaskView.as_view(), name='top_page'),
path('start/<int:pk>', views.Start, name='start'), #ここを追加
]
次にviews.pyに実行するビューを作成します。
views.pyこのビューの中にタスクのステータスを書き換える処理を書きます。
def Start(request, pk):
task = get_object_or_404(Task, pk=pk)
new_status = Status.objects.get(status="Ongoing")
task.status = new_status
task.save()
return redirect('/taskapp')
このビューが実行されるとき、一緒に「pk」という変数が渡されています。
def Start(request, pk):この「pk」は何かというと、着手ボタンに割り当てられていたurlの{{task.id}}の部分になります。
href="/taskapp/start/{{task.id}}"
「task.id」は書き換え対象タスクのID(識別番号のようなもの)です。
この「task.id」が入ったurlがクリックされたことで、urls.pyの'start/<int:pk>'の<int:pk>部分がtask.idに置き換わります。
path('start/<int:pk>', views.Start, name='start'), #ここの<int:pk>の部分
pk = task.id #pkは整数(INT)型
このpk = task.idという情報を持ったままviews.pyのStartビューが実行されます。
つまり
def Start(request, pk): ⇒ def Start(request, task.id):というように解釈できます。
ビューの続きを見ていきましょう。
まず書き換え対象のモデルを変数「task」に格納します。
task = get_object_or_404(Task, pk=pk)ここでTaskモデルのpk(プライマリーキー)をリクエストで受け取ったpk(=task.id)で指定しています。
こうすることで着手ボタンが押されたタスクと同じタスクモデルをビュー内に呼び出すことができます。
続いて「実行中」ステータスを割り当てます。
new_status = Status.objects.get(status="Ongoing")まず「new_status」という変数を用意し、Statusモデルの「status="Ongoing"」を格納します。
task.status = new_status
「task.status」はStatusモデルから選択する形式ですので「task.status = "Ongoing"」という割り当て方はできません。
これはmodels.pyを見たら分かります。
models.py「Status」というモデルからForeignKeyで1つ選択する形式ですね。
status = models.ForeignKey(
Status, verbose_name='状況', on_delete=models.PROTECT)
上記の理由の為、「new_status」というStatusモデル(status="Ongoing")を用意する必要があるのです。
このStatusモデルをTask.statusに割り当てます。
task.status = new_statusこれで、task.statusが "Ongoing"(実行中)に書き換えられました。
書き換えた後はsave()メソッドでモデルを上書き保存します。
task.save()
モデルの更新が終わったので、元のトップページにリダイレクトします。
return redirect('/taskapp')
これでワンクリック変更が完了です。
4.2 - モデル編集
上記のタスク管理の中に歯車アイコンがありますね。
ここを押すと該当タスクの詳細を変更することができます。
上記の例ではタスクの優先度パラメータを「最優先(Urgent」から「低い(Low)」に変更しています。
この編集方法を解説します。
html上の歯車ボタンは下記のように記述し、アイコンが押されたタスクのidを参照し、編集ページに移動するようにします。
html歯車アイコンはFont Awesomeを使用しています。<i class="fas fa-cog"></i>の部分です。
<a href="/taskapp/edit/{{task.id}}" title="編集"><i class="fas fa-cog"></i></a>
Font Awesomeについては別途記事を書こうと思います。ここでは便利なアイコンライブラリと思っておけば大丈夫です。
まだurls.pyに上記ページの設定を作っていないので、作ります。
urls.pyこれで歯車アイコンが押されたときに「TaskEditView」というビューが実行される準備ができました。
urlpatterns = [
path('', views.TaskView.as_view(), name='top_page'),
path('edit/<int:pk>', views.TaskEditView, name='edit'), #ここを追加
path('start/<int:pk>', views.Start, name='start'),
]
次にviews.pyに実行するビューを作成します。
views.py先ほどのワンクリック変更と若干異なりますね。共通部分の説明は割愛します。
def TaskEditView(request, pk):
"""Edit Page"""
task = get_object_or_404(Task, pk=pk)
if request.method == "POST":
form = AddTaskForm(request.POST, instance=task)
if form.is_valid():
form.save()
return redirect('/taskapp')
else:
form = AddTaskForm(instance=task)
return render(request, 'task_edit.html', {'task': task, 'form': form})
まず「if request.method == "POST":」の部分は飛ばして「else:」文を見ましょう。
この編集ページを開くときはGETメソッドで開かれるので、「if request.method == "POST":」は実行されず「else:」が実行されます。
form = AddTaskForm(instance=task)「form」という変数に「AddTaskForm」というフォームが格納されています。
ついでに「instance=task」となっていますね。
AddTaskFormはタスクを追加するときに使用するフォームのことです。
forms.pyで定義しています。
forms.pyこのタスク追加フォームを編集画面でも再利用します。
class AddTaskForm(forms.ModelForm):
"""タスク追加フォーム"""
class Meta:
model = Task
fields = '__all__'
「instance=task」としたことで、このフォーム入力画面には既に登録済みのパラメータが入力された状態で表示されるようになります。
新規追加画面の場合は何もフォームには入っていません。
編集画面ではフォームに元々のデータが入った状態で表示されます。
ビューの続きを見ましょう。
return render(request, 'task_edit.html', {'task': task, 'form': form})「task_edit.html」を表示しつつ、テンプレートに先ほど定義した「form」変数を渡しています。
task_edit.htmlの中身を確認します。
task_edit.html見易いように最低限の項目に絞って書いています。
<form method="POST" class="post-form" class="form-group">
{{ form.non_field_errors }}
<label for="{{ form.task.id_for_label }}">やること:</label>
{{ form.task }}
<label for="{{ form.priority.id_for_label }}">優先度:</label>
{{ form.priority }}
<label for="{{ form.status.id_for_label }}">状況:</label>
{{ form.status }}
{{ form.errors }}
{% csrf_token %}
<div>
<a class="btn btn-outline-danger" href="/taskapp" role="button">
キャンセル
</a>
<button type="submit" class="save btn btn-primary">変更する</button>
</div>
</form>
for文で書けばもっとスッキリしますが、こちらもあえて(略)です。
instance=taskとしたので、ここで表示している3項目のフォーム
「form.task」
「form.priority」
「form.status」
には既にtaskに登録済みのパラメータが入力された状態で表示されます。
さて、それでは編集を行いましょう。
編集画面の「優先度」フォームは「最優先(Urgent)」となっていますので、「低い(Low)」にします。
その後、「変更する」ボタンを押します。
「変更する」ボタンはhtml上ではこのように書かれています。
<button type="submit" class="save btn btn-primary">変更する</button>「button type="submit"」なので、ボタンを押すとフォームの入力内容が送信されます。
フォームが送信(=POST)されると、views.pyで先ほど説明を飛ばした「if request.method == "POST":」の部分が実行されます。
views.py「form」という変数に送信されたフォームの内容を入れます。
if request.method == "POST":
form = AddTaskForm(request.POST, instance=task)
if form.is_valid():
form.save()
return redirect('/taskapp')
ここで重要なのが第二引数の「instance=task」の部分です。
この引数が無いとDjangoは送信されたデータが新しいTaskモデルだと認識するので、新規タスクの追加になってしまいます。
当初の目的はタスクの編集(=上書き)ですので、上書きする対象を第二引数で指定します。
その後、通常通りフォームの入力内容にミスが無ければタスクの保存処理に移ります。
if form.is_valid():
form.save()
上書き保存が完了した後、元のトップページにリダイレクトします。
return redirect('/taskapp')
これで編集作業が完了となります。
5. さいごに
以上、2通りのモデル変更方法を解説しました。
実際に自分でいじってみると理解が深まると思いますので、失敗しながらトライしてみて下さい。
お疲れ様でした。