前回の記事では記事表示と記事作成の機能をそれぞれ実装しました。
今回は記事を削除する機能を実装します。
シンプルな機能実装
記事の削除は機能実装としては非常に簡単で、view関数は以下の通りです。
# 删文章
def article_delete(request, id):
# 根据 id 获取需要删除的文章
article = Article.objects.get(id=id)
# 调用.delete()方法删除文章
article.delete()
# 完成删除后返回文章列表
return redirect("list")
- 記事のクエリと同様に、どの記事を削除する必要があるかを知る必要があるため、記事の ID を渡す必要があります。
- 次に、.delete() 関数を呼び出して、データベース内のこの記事のエントリを削除します。
- 削除が成功したら記事リストに戻ります。
次に、ルーティング構成ドキュメントを変更します。
urlpatterns = [
path('admin/', admin.site.urls),
path('hello/', views.hello),
re_path(r'^$', views.article_list),
path('list/', views.article_list, name='list'), # 展示文章
path('detail/<int:id>/', views.article_detail, name='detail'), # 文章详情
path('create/', views.article_create, name='create'), # 写文章
# 增加生删除文章
path('delete/<int:id>/', views.article_delete, name='delete'),
]
最後に、テンプレートを変更し、detail.html
詳細ページに記事を削除するボタンを追加します。
<!-- 文章详情 -->
<div class="container">
<!-- <div class="row">-->
<!-- 标题及作者 -->
<h1 class="col-12 mt-4 mb-4">{
{ article.title }}</h1>
<div class="col-12 alert alert-primary">
<div class="col-12">
<a>作者:{
{ article.author }}</a>
 
<a>{
{ article.created|date:'Y-m-d H:i:s' }}</a>
 
<a href="{% url "delete" article.id %}">删除文章</a> #增加此项
</div>
</div>
<!-- 文章正文 -->
<div class="col-12">
<p>{
{ article.body }}</p>
</div>
</div>
サーバーを実行すると、記事の削除ボタンが追加されていることがわかります。
ポップアップ確認機能を削除
上記は単純な機能を実装していますが、誤って削除ボタンをクリックすると、後悔する機会すらなくなる可能性があるという危険が隠れています。
一般に、データの直接消去を伴うアクションの場合、ポップアップ ウィンドウの確認アクションが必要であり、データベース データは 2 回目の確認後にのみ直接削除できます。
この機能を実現するには、Bootstrap のモーダル コンポーネントを使用します。
モーダルは、親フォームをオーバーレイするサブフォームです。通常、その目的は、親フォームを離れることなく何らかの対話が可能な別のソースからのコンテンツを表示することです。サブフォームは情報のやり取りなどを提供できます。
detail.html
新しく追加した行の前の記事コードを削除し、次の変更を加えます。
<a href="#" data-bs-toggle="modal" data-bs-target="#myModal">删除文章</a>
モーダル ボックス効果が追加されました。このリンクをクリックすると、myModal
という名前のモーダル ボックスがポップアップ表示されます。
次にmyModal
モーダルボックス内の記事を削除する機能を実装します。
<!-- 模态框 -->
<div class="modal fade" id="myModal">
<div class="modal-dialog modal-dialog-centered modal-sm">
<div class="modal-content">
<!-- 模态框头部 -->
<div class="modal-header">
<h4 class="modal-title">确认删除</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<!-- 模态框主体 -->
<div class="modal-body">
确认删除文章?
</div>
<!-- 模态框底部 -->
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" data-dismiss="modal" onclick="confirm_delete()">
确定
</button>
</div>
</div>
</div>
</div>
<script>
// 删除文章的函数
function confirm_delete() {
location.href = '{% url "delete" article.id %}'
}
</script>
ここでは実際に 2 つの関数を実装します。
- myModal という名前のモーダル ボックスが実装され、モーダル ボックスに [キャンセル] と [確認] の 2 つのボタンが追加されます。「確認」をクリックすると、JS 関数が呼び出され
confirm_delete()
、記事を削除します。 confirm_delete()
Django の削除記事を呼び出してurl:delete
削除機能を実装する関数を書きました。
安全な方法
記事を削除する機能の実装は難しくないと思われるかもしれませんが、上記の方法には危険が隠れていることに注意してください。さらに詳しい議論を続けるには、CSRF 攻撃(クロスサイト リクエスト フォージェリ)とも呼ばれる、クロスサイト リクエスト フォージェリ攻撃について言及する必要があります。
CSRF攻撃
CSRF 攻撃は、攻撃者があなたの ID を盗み、あなたの名前を使って悪意のあるリクエストを送信するものとして理解できます。例として記事を削除してみましょう。
- ユーザーはブログ Web サイト Aにログインし、ブラウザはセッションを記録し、ログイン状態を維持しました。
- ユーザーは誤ってログアウトせずに邪悪な攻撃 Web サイト Bを開いてしまいました。
- 攻撃サイトBは、ページ内に悪意のあるコードを埋め込み、ブログサイトAに記事の削除リクエストをサイレントに送信します。このとき、ブラウザはユーザーが操作していると誤認し、削除操作に成功します。
ブラウザの同一オリジン ポリシーにより、CSRF 攻撃者はログイン データの実際の内容を取得することはできませんが、ブラウザをだまして正しいログイン データを悪意のあるリクエストに添付させることができます。CSRF 攻撃の威力を過小評価しないでください。銀行口座にそのようなセキュリティ ホールがある場合、ハッカーは誰にも気付かれずに預金をすべて送金することができます。
では、ここで CSRF 攻撃のリスクを防ぐにはどうすればよいでしょうか? 記事削除時にPOSTメソッドを使用し、csrfトークンを確認する方法があります。
CSRFトークン
Django でフォームを送信するときに csrf_token を追加する必要があると前述しましたが、これは CSRF トークンであり、CSRF 攻撃を防ぐプロセスは次のとおりです。
- ユーザーが Django サイトにアクセスすると、Django によってユーザーにフィードバックされるフォームに暗黙的なフィールド csrf_token があり、この値はサーバー側でランダムに生成され、毎回異なります。
- バックエンドが POST リクエストを処理する前に、Django はリクエストされた Cookie 内の csrf_token がフォーム内の csrf_token と一致するかどうかを検証します。一致していればリクエストは正当ですが、そうでない場合はリクエストは CSRF 攻撃によるものである可能性があり、403 Server Forbidden Access が返されます。
攻撃者はユーザーの Cookie コンテンツを取得できないため (ブラウザーの転送に依存するだけ)、通常は正しい csrf_token を構築することが不可能であるため、このような攻撃を防ぐことができます。
フォームを使用して投稿リクエストを送信する
Django で Post リクエストを送信するには、フォームでリクエスト メソッドを指定できます。
まず、記事削除ボタンのコードの下に非表示のフォームを追加します。
<a href="#" data-bs-toggle="modal" data-bs-target="#myModal">删除文章</a>
<!-- 新增一个隐藏的表单 -->
<form
style="display:none;"
id="safe_delete"
action="{% url "delete" article.id %}"
method="POST"
>
{% csrf_token %}
<button type="submit">发送</button>
</form>
次にconfirm_delete()
関数を変更します。
<script>
// 删除文章的函数
function confirm_delete() {
document.getElementById("safe_delete").submit();
}
</script>
最後に、ビュー関数を変換します。
# 删文章
def article_delete(request, id):
print(request.method)
if request.method == 'POST':
# 根据 id 获取需要删除的文章
article = Article.objects.get(id=id)
# 调用.delete()方法删除文章
article.delete()
return redirect("list")
else:
return HttpResponse("仅允许post请求")
以前の機能では、URL を直接呼び出して Django のビュー削除機能をリクエストしていました。
変換後の記事を削除するコード プロセスは次のようになります。
- 記事を削除するリンクをクリックすると、モーダル ボックスが表示されます
- モーダルボックスの確認ボタンをクリックした後、JS関数コードを介して隠れたフォームを見つけてフォームを送信します。
- フォームは POST リクエストを開始し、csrf トークンを送信します (Django はデフォルトでミドルウェアを通じてすべての POST リクエストを検証します
csrf
)。これにより、csrf 攻撃を回避します。
結論
この記事では、記事を削除する機能の実装方法を学び、また、Bootstrap のモーダル ポップアップ ボックスを使用して、削除された記事の二次検証を実行しました。
削除機能に関しては、データのセキュリティを高めるために、Django のcsrf
トークン保護メカニズムを簡単に導入し、crsf
隠しフォームを使用して Post リクエストを送信することで Django の検証メカニズムを有効にしました。
実は削除機能にはユーザー認証という重要な検証があるのですが、これについてはまだ説明していませんので、後ほどユーザーモジュールの機能を追加する際に追加する予定です。
次の記事では、記事を更新する方法を学びます。