[Django]プロフィール表示・編集・退会

前回の続きでUser関連の操作のTipを少し。

環境:django2.**

プロフィール表示

ユーザーごとのプロフィールページを作成しましょう。DetailViewを使います。users/views.pyにこちらを。

class ProfileDetailView(generic.DetailView):
    model = User
    slug_field = 'username'
    slug_url_kwarg = 'username'
    template_name = 'users/profile.html'

    def get_context_data(self, **kwargs):
        context = super(ProfileDetailView, self).get_context_data(**kwargs)
        username = self.kwargs['username']
        context['username'] = username
        context['user'] = self.request.user
        return context

urls.pyに追加します。

path('<str:username>/', views.ProfileDetailView.as_view(), name='profile'),

次にテンプレートの作成です。templates/users/profile.htmlを。

{% extends 'base.html' %}

{% block body %}
  <h1>@{{ username }}</h1>
{% endblock %}

これでユーザー詳細ページができました。

プロフィール編集

プロフィール編集ができるようにしてみます。

users/forms.pyにEditFormを作りましょう。

class ProfileEditForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ('name', 'email', 'username', 'icon', 'about_me',)

    def __init__(self, *args, **kwargs):
        super(ProfileEditForm, self).__init__(*args, **kwargs)

        for field_name, field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'

そして、users/views.pyの方も記述していきます。今回は編集なので、UpdateViewを使います。

class ProfileEditView(UpdateView):
    model = User
    form_class = ProfileEditForm
    template_name = 'users/edit.html'
    slug_field = 'username'
    slug_url_kwarg = 'username'

users/urls.pyにもきちんと書いとく。

path('<str:username>/edit', views.ProfileEditView.as_view(), name='edit'),

先ほどのprofile.htmlに下記を追記しといてください。

{% if user.username == username %}
<a href="{% url 'users:edit' username %}">編集</a>
{% endif %}

そして、templates/users/edit.htmlを作成します。

{% extends 'base.html' %}

{% block body %}
<form role="form" method="post" enctype="multipart/form-data">
  {% csrf_token %}
  <h3>プロフィール変更</h3>
  <div>
    <label for="id_name">ユーザー名:</label>
    {{ form.name }}
  </div>
  <div>
    <label for="id_email">メールアドレス:</label>
    {{ form.email }}
  </div>
  <div>
    <label for="id_username">ユーザーID:</label>
    {{ form.username }}
  </div>
  <div>
    <button type="submit">変更</button>
  </div>
</form>
{% endblock %}

編集ページができました!

自分のページにだけアクセスする

ここで一つ問題があります。URLから他人のデータを編集することができてしまいます。制限をかけときましょうか。

from django.contrib.auth.mixins import UserPassesTestMixin

class OnlyYouMixin(UserPassesTestMixin):
    raise_exception = True

    def test_func(self):
        user = self.request.user
        return user.username == self.kwargs['username'] or user.is_superuser

これをProfileEditViewに継承させときます。

class ProfileEditView(OnlyYouMixin, UpdateView):

これで自分の編集ページだけしかアクセスできないようになりました。

退会

最後に退会機能を実装しておきます。DeleteViewを使います。

class UserDeleteView(OnlyYouMixin, generic.DeleteView):
    template_name = "users/delete.html"
    success_url = reverse_lazy("users:index")
    model = User
    slug_field = 'username'
    slug_url_kwarg = 'username'

urls.pyにも追記。

path('<str:username>/delete/', views.UserDeleteView.as_view(), name='delete'),

profile.htmlにこれを記述しとく。

{% if user.username == username %}
<a href="{% url 'users:edit' username %}">編集</a>
<a href="{% url 'user_auth:delete' username %}">退会</a><
{% endif %}

そして、templates/users/delete.htmlを作成して、完成!

{% extends 'base.html' %}

{% block body %}
<h1>退会</h1>

<form role="form" method="post">
  {% csrf_token %}
  <p>あなたのアカウント「@{{ user.username }}」を、本当に削除してもよろしいですか?</p>

  <button type="submit">削除</button>
</form>
{% endblock %}