Djangoアプリにアクセス制御を追加する方法を学びましょう。投稿はログインユーザーのみ、投稿の編集・削除はその投稿を作成したユーザーのみが行えるようにします。これもDjangoが用意してくれている機能で簡単に実現できます。
目次
views.pyにアクセス制御を追加
まずはアクセス制御を実装しましょう。
Djangoアプリにアクセス制御を実装するには views.py で LoginRequiredMixin をインポートしてログイン時だけ利用できるようにしたいクラスで継承します。
bbsアプリのviews.pyに次のように記述します。
from django.urls import reverse_lazy from django.views import generic from .models import Article from django.contrib.auth.mixins import LoginRequiredMixin # インポート class IndexView(generic.ListView): model = Article class DetailView(generic.DetailView): model = Article class CreateView(LoginRequiredMixin, generic.edit.CreateView): # 継承 model = Article fields = '__all__' class UpdateView(LoginRequiredMixin, generic.edit.UpdateView): # 継承 model = Article fields = '__all__' class DeleteView(LoginRequiredMixin, generic.edit.DeleteView): # 継承 model = Article success_url = reverse_lazy('bbs:index')
LoginRequiredMixin をインポートして、新規投稿を作成するCreateView、投稿を更新するUpdateView、投稿を削除するDeleteViewクラスはそれを継承することで、アクセス制御を追加しました。
ログインしていないユーザーでも投稿を閲覧するだけならできるようにしておくため、IndexViewとDetailViewには追加していません。
動作確認
それでは動作確認です。
Djangoコマンドを使ってサーバーを起動し、ブラウザで確認してみましょう。
http://127.0.0.1:8000/accounts/login/ にアクセスします。
現在ログインしていない状態です。非ログイン時の動作を確認したいので、ログイン状態になっている場合はログアウトしておいて下さい。
では、http://127.0.0.1:8000/bbs にアクセスします。
ログインしていない状態でも投稿一覧を閲覧することができます。
「こんちゃっす」をクリックして個別投稿ページにアクセスしてみましょう。
このページも閲覧は可能です。
では「編集」をクリックしてみましょう。
ログインページにリダイレクトされました。
投稿を新規に作成しようとしたり、削除しようとしてもログインページにリダイレクトされます。
このようにDjangoにアクセス制御を追加するとログインしているユーザーだけが操作できる機能を実現することができます。
ログイン時だけ項目を表示
新規投稿はログインユーザーしかできないようにしたので、ログイン時だけ表示されるよう修正しましょう。
article_list.html を次のように修正します。
{% extends "./base.html" %} {% block content %} <h1>Djangoで学ぶアクセス制御</h1> {% for article in object_list %} <p> <a href='{% url "bbs:detail" article.id %}'>{{ article.content }}</a> {{ article.user_name }} </p> {% endfor %} <!-- ログインしている場合 --> {% if user.is_authenticated %} <div> <button onclick='location.href="{% url "bbs:create" %}"'>新規投稿</button> </div> {% endif %} {% endblock %}
user.is_authenticated を呼び出すことでログイン状態かどうかを判断することができます。
あとはif文で条件が True の場合のみ表示したい項目を記述するだけです。
ユーザー自身の投稿だけを編集可能にする
次は投稿の編集・削除リンクを、その投稿を作成したユーザーのみに表示するようにしましょう。
article_detail.html を次のように修正します。
{% extends "./base.html" %} {% block content %} <h1>{{ article.id }}の個別投稿ページ</h1> <p>{{ article.content }}, {{ article.user_name }}</p> <div> <button onclick='location.href="{% url "bbs:index" %}"'>一覧</button> <!-- ユーザー名がその投稿のものと一致する場合 --> {% if request.user.username == object.user_name %} <button onclick='location.href="{% url "bbs:update" article.pk %}"'>編集</button> <button onclick='location.href="{% url "bbs:delete" article.pk %}"'>削除</button> {% endif %} </div> {% endblock %}
ログインしているユーザー名(request.user.username)と投稿作成者のユーザー名(object.user_name)が一致する場合のみ「編集」と「削除」のリンクを表示しています。
動作確認
それでは動作確認です。
Djangoコマンドを使ってサーバーを起動し、ブラウザで確認してみましょう。
http://127.0.0.1:8000/bbs にアクセスします。
非ログイン状態なので「新規投稿」ボタンが表示されなくなっているのがわかります。
http://127.0.0.1:8000/accounts/login にアクセスしてログインしてみましょう。
今度はログイン状態なので「新規投稿」ボタンが表示されています。
そのまま「新規投稿」をクリックして投稿を作成してみましょう。
User name をログイン中のユーザー名と同じにしておいて下さい。
「作成」をクリック
ログインしているユーザー名と投稿作成者のユーザー名が一致しているので、「一覧」「編集」「削除」すべてのリンクが表示されています。
ログアウトした状態でもう一度この投稿のページにアクセスすると、次のように「一覧」へのリンクだけが表示されます。
なお、この記事はあくまでアクセス制御を体験するための簡単なデモンストレーションです。
実際にはこの方法ではユーザー名を参照しているため、同一ユーザーかどうかをきちんと特定することができません。実用アプリケーションを作る場合は投稿時にログインユーザーのIDを自動的に格納するなどして、ログインユーザーと投稿ユーザーが同じかどうかきちんとチェックできるようにしましょう。
またこれだけだと自分の投稿でなければリンクが表示されないだけであって、ログイン状態でありさえすれば、URLを直接叩くことでユーザー名が異なる投稿でも削除できてしまいます。