18.Djangoアプリでログイン時だけ投稿・編集を可能にしてみよう

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を直接叩くことでユーザー名が異なる投稿でも削除できてしまいます。

このエントリーをはてなブックマークに追加

コメントを残す

頂いたコメントは一読した後表示させて頂いております。
反映まで数日かかる場合もございますがご了承下さい。