Pythonメモ torinaブログ

このブログはDjangoとBootstrap4で作成されました
ソースコード

Djangoで、パーミッションを扱う②

プログラミング関連 Django
約176日前 2016年10月1日20:41
Djangoで、パーミッションを扱う①
https://torina.top/main/295/

の続きです。今回はユーザ登録の際に、自動でパーエミッションを付与しましょう。

トップページに、ユーザの追加が増えました。


権限の設定で、いくつかの権限を選びます。これはMessageモデルを追加する権限を付与します。


user1でログインすると、Messageの追加以外はできなくなります。


管理画面にも、ちゃんと適用されていますね。


こちらはグループの権限を追加します。


以前作ったグループは、編集と削除ができるものでした。投稿はできません。



管理画面にもグループが追加されています。


Django1.10
Python3.5
プロジェクト名「project」
アプリケーション名「app」
です。前回からの変更点のみ書いていきます。

project/app/templates/app/post_list.html
ユーザ追加のリンクが増えました。perms.auth.add_userですが、これはユーザ追加の権限があるか?ということです。
ユーザ追加ができるユーザを作る際は、この権限をつけときましょう。
{% extends "app/base.html" %}
{% block content %}
  {% if perms.app.add_message %}
    <p><a href="{% url 'app:add' %}">新規追加</a></p>
  {% endif %}

  <!-- たした -->
  {% if perms.auth.add_user %}
    <p><a href="{% url 'app:create_user' %}">ユーザの追加</a></p>
  {% endif %}

  <hr>
  {% for message in message_list %}
    <p>
      {{ message.text }}
      
      {% if perms.app.change_message %}
        <a href="{% url 'app:change' message.pk %}">変更する</a>
      {% endif %}
      
      {% if perms.app.delete_message %}
        <a href="{% url 'app:delete' message.pk %}">削除する</a>
      {% endif %}

    </p>
  {% endfor %}
{% endblock %}


補足ですが、以下のコマンドで作ったスーパーユーザはis_superuserがTrueのユーザで、全ての権限を持っているのと同じ状態になります。
python manage.py createsuperuser



project/app/templates/app/user_form.html
message_formとかわらないです。
{% extends "app/base.html" %}
{% block content %}
  <form action="" method="POST">
    {{ form.as_p }}
    {% csrf_token %}
    <input type="submit" value="送信">
  </form>
{% endblock %}



project/app/urls.py
urls.pyにも追加しましょ
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.MesIndexView.as_view(), name='index'),
    url(r'^add/$', views.MesAddView.as_view(), name='add'),
    url(r'^change/(?P<pk>[0-9]+)/$', views.MesChangeView.as_view(), name='change'),
    url(r'^delete/(?P<pk>[0-9]+)/$', views.MesDeleteView.as_view(), name='delete'),

    url(r'^create_user/$', views.UserCreateView.as_view(), name='create_user'),  # add
]


project/app/forms.py
UserCreationFormはユーザ作成用のフォームです。右上のクイックサーチで検索すると、過去に説明しているものが出てきます。
加えて、単純なPermission付与かグループの付与かを選べるフィールドも作りました。
from django import forms
from django.contrib.auth.forms import UserCreationForm


KIND = (
    ("user", "権限を追加(投稿のみ)"),
    ("group", "グループの権限を追加(編集と削除)"),
)


class UserCreateForm(UserCreationForm):
    kind = forms.ChoiceField(label="権限の設定", choices=KIND)


project/app/views.py
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.auth.models import Permission, Group  # 増えた
from django.core.urlresolvers import reverse_lazy
from django.http import HttpResponseRedirect  # 増えた
from django.views import generic
from .models import Message
from .forms import UserCreateForm  # 増えた


class MesIndexView(generic.ListView):
    model = Message


class MesAddView(PermissionRequiredMixin, generic.CreateView):
    model = Message
    fields = "__all__"
    success_url = reverse_lazy("app:index")
    permission_required = ("app.add_message")
    raise_exception = True


class MesChangeView(PermissionRequiredMixin, generic.UpdateView):
    model = Message
    fields = "__all__"
    success_url = reverse_lazy("app:index")
    permission_required = ("app.change_message",)
    raise_exception = True


class MesDeleteView(PermissionRequiredMixin, generic.DeleteView):
    model = Message
    fields = "__all__"
    success_url = reverse_lazy("app:index")
    permission_required = ("app.delete_message",)
    raise_exception = True


# 増えた
class UserCreateView(PermissionRequiredMixin, generic.CreateView):
    form_class = UserCreateForm
    template_name = "app/user_form.html"
    success_url = reverse_lazy("app:index")
    permission_required = ("auth.add_user")
    raise_exception = True

    def form_valid(self, form):
        user = form.save(commit=False)
        user.is_staff = True
        user.save()
        kind = form.cleaned_data["kind"]
        if kind == "user":
            permission = Permission.objects.get(codename="add_message")
            user.user_permissions.add(permission)

        elif kind == "group":
            group = Group.objects.get(name='変更と削除')
            user.groups.add(group)
        else:
            pass  # ここには「基本的」に来ない。raise Http404 とかしといても良いかもしれない

        return HttpResponseRedirect(self.success_url)



PermissionRequiredMixinを継承し、権限でコントロールできるようにします。
auth.add_userはユーザ追加の権限があるか?です。
raise_exception = Trueは、権限を持ってなかった場合に403ページへ飛ばします。
class UserCreateView(PermissionRequiredMixin, generic.CreateView):
    form_class = UserCreateForm
    template_name = "app/user_form.html"
    success_url = reverse_lazy("app:index")
    permission_required = ("auth.add_user")
    raise_exception = True


汎用ビューでは、既に処理の流れはある程度定義されており、カスタマイズする場合はクラス変数や、一部のメソッドを上書きします。
adminにログインできるようis_staffをTrueにし、formのkindを取得します。
その後、Permissionを追加したり、グループを追加しているわけですね。
super().__init__等でもよかったんですが、特にさせることもないので、ここでリダイレクトさせています。
    def form_valid(self, form):
        user = form.save(commit=False)
        user.is_staff = True
        user.save()
        kind = form.cleaned_data["kind"]
        if kind == "user":
            permission = Permission.objects.get(codename="add_message")
            user.user_permissions.add(permission)

        elif kind == "group":
            group = Group.objects.get(name='変更と削除')
            user.groups.add(group)
        else:
            pass  # ここには「基本的」に来ない。raise Http404 とかしといても良いかもしれない

        return HttpResponseRedirect(self.success_url)