見出し画像

djangoで作る本格的なSNSアプリケーション 番外編 allauthによる認証

djangoで簡単なTodoアプリ等は作成できたけれども、オリジナルWebアプリを作る前にもう少しだけ本格的なアプリをチュートリアル形式で取り組みたい方を対象としています。

Part1Part2で作成したaccountsアプリをDjango-allauthで実装してみたいと思います。allauthを使うとユーザー認証機能がとても簡単に実装できますので、どれほど簡単になるのかの比較にもなるかと思います。


ソースコードは、Githubに載せておりますのでそちらも参照ください。

目標

django-allauthを実装し、SNSアプリのaccountsアプリを作成出来るようになります。クラスベース汎用ビューを前提として開発を進めます。

開発環境、前提条件、IDEの設定

Part1と同じほぼ環境と前提で開発していきますので、そちらをご覧ください(IDEはPycharmを使用しています)。

仮想環境と必要なパッケージ

・django_envという仮想環境を作成し
・django3.2.4
・Pillow
・django-bootstrap4
・bcrypt
・beautifulsoup4
・django-allauth(0.41.0) ⇦ 今回追加

開発の手順のおさらい

①sns2プロジェクトの開始とアプリの作成 
②ユーザーモデルとユーザー登録機能 ← Allauthで実装
③ログイン、ログアウト機能 ← Allauthで実装
④ユーザー情報の更新と一覧表示 ← Allauthで実装
⑤ポストモデルとCRUD操作
⑥ユーザのFollow/Unfollow機能の追加
⑦ポストのお気に入り機能追加

SNS2プロジェクトの開始と初期設定

 プロジェクト名をallauth有無で分けるためsns2とします。sns2プロジェクトを開始し、accountsアプリを作成します。まずは、sns2プロジェクトを保存するフォルダーにターミナルで移動します。今回は、django_projectsというフォルダー内にsns2プロジェクトを作成します。

python manage.py startapp accounts

これから必要となるフォルダーやファイルを最初に作ります。画像を確認して下さい(VisualStudioCodeではなく、Pycharmの画面になりますがご了承ください)。特に気をつけていただきたいのは、templates内のaccountフォルダです。accountsではなく、accountです。allauthlogin.htmlなどを上書きする予定ですので、わざとaccountにしています。

画像1

設定ファイル(settings.py)の編集

 これまでに作成したアプリ、パッケージ、フォルダーなどが使えるようにsettings.pyを変更していきます。settings.pyのコードは以下のようになります。

 sns2/settings.py

from pathlib import Path
import os  # 追加
from django.contrib.messages import constants as messages  # 追加
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-89v+92f@u!49l7&4nd8k=)h7iqz$2$bloy%c=i&#5u2j!xe46f'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
   'django.contrib.admin',
   'django.contrib.auth',
   'django.contrib.contenttypes',
   'django.contrib.sessions',
   'django.contrib.messages',
   'django.contrib.staticfiles',
   'accounts',  # 追加
   'bootstrap4',  # 追加
   'django.contrib.sites',  # 追加
   'allauth',  # 追加
   'allauth.account',  # 追加
   'allauth.socialaccount',  # 追加
]
SITE_ID = 1
LOGIN_REDIRECT_URL = '/accounts/home'
ACCOUNT_LOGOUT_REDIRECT_URL = 'account_login'
ACCOUNT_EMAIL_VERIFICATION = 'none'
MIDDLEWARE = [
   'django.middleware.security.SecurityMiddleware',
   'django.contrib.sessions.middleware.SessionMiddleware',
   'django.middleware.common.CommonMiddleware',
   'django.middleware.csrf.CsrfViewMiddleware',
   'django.contrib.auth.middleware.AuthenticationMiddleware',
   'django.contrib.messages.middleware.MessageMiddleware',
   'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'sns2.urls'
TEMPLATES = [
   {
       'BACKEND': 'django.template.backends.django.DjangoTemplates',
       'DIRS': [BASE_DIR / 'templates']  # VSCodeの場合は変更
       ,
       'APP_DIRS': True,
       'OPTIONS': {
           'context_processors': [
               'django.template.context_processors.debug',
               'django.template.context_processors.request',
               'django.contrib.auth.context_processors.auth',
               'django.contrib.messages.context_processors.messages',
           ],
           # Bootstrap4を使用するために追加
           'builtins': [
               'bootstrap4.templatetags.bootstrap4', ]
       },
   },
]
WSGI_APPLICATION = 'sns2.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {
   'default': {
       'ENGINE': 'django.db.backends.sqlite3',
       'NAME': BASE_DIR / 'db.sqlite3',
   }
}
# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
   {
       'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
   },
   {
       'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
   },
   {
       'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
   },
   {
       'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
   },
]
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'ja'  # 変更
TIME_ZONE = 'Asia/Tokyo'  # 変更
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
# 追加
STATICFILES_DIRS = (
   os.path.join(BASE_DIR, "static"),
)
# 追加 mediaを扱うための設定
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# 追加
IMAGE_URL = '/images/'
IMAGE_ROOT = os.path.join(BASE_DIR, 'images')
# 追加 メッセージタグの設定
MESSAGE_TAGS = {
   messages.ERROR: 'alert alert-danger',
   messages.WARNING: 'alert alert-warning',
   messages.SUCCESS: 'alert alert-success',
   messages.INFO: 'alert alert-info'
}
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# 一番下に追加
AUTH_USER_MODEL = 'accounts.CustomUser'
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_LOGOUT_ON_GET = True、設定も実施してしまいます。

 allauthを使用するために、INSTALLE _APPSに3つ追加しています。また、SITE _ID = 1はallauthを使用する際の決まりであり、それ以下はURLの認証等に必要ですので追加して下さい。

INSTALLED_APPS = [
・・・省略・・・
   'allauth',  # 追加
   'allauth.account',  # 追加
   'allauth.socialaccount',  # 追加
]
SITE_ID = 1  # 追加
LOGIN_REDIRECT_URL = '/accounts/home'  # 追加
ACCOUNT_LOGOUT_REDIRECT_URL = 'account_login'  # 追加
ACCOUNT_EMAIL_VERIFICATION = 'none'  # 追加

後ほどプロフィール画像を登録できるようにしていきますが、プロフィール画像はimagesフォルダーへ保存するようにしますので、その設定も追記していきましょう。

IMAGE_URL = '/images/'
IMAGE_ROOT = os.path.join(BASE_DIR, 'images')

また、ユーザーモデルをCustomUserとして作成しますので、ユーザーモデルを設定します。ACCOUNT_AUTHENTICATION_METHOD = 'email'では、認証方法をusernameではなくemailとして設定します。また、usernameは今回使用しませんので不要とします。

# 一番下に追加
AUTH_USER_MODEL = 'accounts.CustomUser'  # 追加
ACCOUNT_AUTHENTICATION_METHOD = 'email'  # 追加
ACCOUNT_USER_MODEL_USERNAME_FIELD = None  # 追加
ACCOUNT_EMAIL_REQUIRED = True  # 追加
ACCOUNT_USERNAME_REQUIRED = False  # 追加
ACCOUNT_LOGOUT_ON_GET = True

sns2/urls.pyの設定ですが、mediaやStaticフォルダを使う設定飲み実施します。まだ、この段階ではaccountsやallauthへパスを通さないで下さい。マイグレーション事にエラーが出ます。

from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static  # mediaを使うために追加
from . import settings  # mediaを使うために追加
urlpatterns = [
   path('admin/', admin.site.urls),
]
if settings.DEBUG:
   urlpatterns += static(settings.IMAGE_URL, document_root=settings.IMAGE_ROOT)  # 追加
   urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)  # 追加

これで最初の設定が終わりましたので、次はカスタムユーザーを作成します。

CustomUserモデル作成とマイグレーション

 これからカスタムユーザーを作ってマイグレーションを実施します。accounts/ models.pyを開いて下さい。最終的なコードは以下になります。

 accounts/models.py

from django.db import models
from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import UserManager, PermissionsMixin
# Create your models here.
class UserManager(UserManager):
   def _create_user(self, email, password, **extra_fields):
       email = self.normalize_email(email)
       user = self.model(email=email, **extra_fields)
       user.set_password(password)
       user.save(using=self._db)
       return user
   def create_user(self, email, password=None, **extra_fields):
       extra_fields.setdefault('is_staff', False)
       extra_fields.setdefault('is_superuser', False)
       return self._create_user(email, password, **extra_fields)
   def create_superuser(self, email, password, **extra_fields):
       extra_fields.setdefault('is_staff', True)
       extra_fields.setdefault('is_superuser', True)
       if extra_fields.get('is_staff') is not True:
           raise ValueError('Superuser must have is_staff=True.')
       if extra_fields.get('is_superuser') is not True:
           raise ValueError('Superuser must have is_superuser=True.')
       return self._create_user(email, password, **extra_fields)

class CustomUser(AbstractBaseUser, PermissionsMixin):
   email = models.EmailField('メールアドレス', unique=True)
   nickname = models.CharField('ニックネーム', max_length=50)
   # プロフィール画像をavatarとして設定
   avatar = models.ImageField(upload_to='images', verbose_name='プロフィール画像', blank=True, null=True)
   is_active = models.BooleanField(default=True)
   is_staff = models.BooleanField(default=False)
   objects = UserManager()
   
   USERNAME_FIELD = 'email'
   EMAIL_FIELD = 'email'
   REQUIRED_FIELDS = []
   
   class Meta:
       verbose_name = ('user')
       verbose_name_plural = ('users')
   def clean(self):
       super().clean()
       self.email = self.__class__.objects.normalize_email(self.email)

 CustomUserモデルには、usernameを使用しない代わりにnicknameを設定します。また、プロフィール画像をmedia/imagesフォルダ内にアップロードするため、avatar = models.ImageField(upload_to='images', verbose_name='プロフィール画像', blank=True, null=True)とします。また、emailをユーザーを識別する唯一の情報としますのでUSERNAME_FIELD = 'email'とします。
 ユーザーモデルが作成できましたので、マイグレーションをおこないます。以下の画像のようにデータベースが作成されていれば成功です。もし、マイグレーションでエラーが発生してしまった場合は、これ以前に一度マイグレーションしていないか思い出してみて下さい。モデル定義前にマイグレーションをかけてしまうと解決が難しいので、素直にもう一度プロジェクトを作成し直した方が時短になります。

python manage.py makemigrates
python manage.py migrate
画像2

allauthによる認証機能の実装

 モデルが完成しましたので、通常であればviews.pyやforms.pyを作成するのですが、allauthがログイン、ログアウト、サインイン等の基本的な機能を備えています。このため、特別な事をしないのであれば改めて作成する必要はありません。することは、パスを通して見た目すだけになります。allauthを使えるようにするために、sns2/urls.pyとaccounts/urls.pyにパスを通します。
 sns2/urls.pyにはallauthとaccountsのurlsが使えるように設定します。allauthのurlと言われてもピンと来ないと思いますがsite-packages/allauth以下にurls.pyが保存されています。そこで基本的なパスは既に設定させています。

 sns2/urls.py

from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static  # mediaを使うために追加
from . import settings  # mediaを使うために追加
urlpatterns = [
   path('admin/', admin.site.urls),
   path('accounts/', include('allauth.urls')),  # 追加
   path('accounts/', include('accounts.urls')),  # 追加
]

if settings.DEBUG:
   urlpatterns += static(settings.IMAGE_URL, document_root=settings.IMAGE_ROOT)  
   urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)   
画像3

 accounts/urls.pyにもパスを通します。特になくても困らないですが、トップページとしてHomeViewを作成しました。

 accounts/urls.py

from django.urls import path
from .views import HomeView

app_name = 'accounts'
urlpatterns = [
   path('home/', HomeView.as_view(), name='home'),
]

allauthへ自作テンプレートを適用

 allauthはテンプレートも準備してくれています。しかし、そのままでは以下のような味気ないテンプレートになってしまいます。自分好みのテンプレートを作成して、allauthの標準テンプレートを上書きしていきます。

ログインallauth
サインアップallauth

 まずは、出来上がりイメージを掴んで下さい。bootstrapを適用しています。djangoで作る本格的なSNSアプリケーションPar 1,Part2とほぼ同じ見た目になります。usernameが不要になった事、ユーザー登録時はパスワードを2回入力することになった事以外はほぼ同じです。

スクリーンショット 2021-06-21 午後20.55.53 午後
スクリーンショット 2021-06-21 午後20.55.59 午後

まずは、base.htmlを作成します。Part1, Part2の時からの使い回しですので変更を加えた部分のみ説明します。

 templates/base.html

{% load static %}
<!DOCTYPE html>
<html lang="ja">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
   <title>Microposts</title>
   {# bootstrapのCSS、自作のCSSを読み込む#}
   <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
         integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
   <link rel="stylesheet" href="{% static 'style.css' %}">
   {% load bootstrap4 %}
</head>
<body>
<header class="mb-4">
   <nav class="navbar navbar-expand-sm navbar-dark bg-dark">
       <a class="navbar-brand" href="#">Microposts</a>
       <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent">
           <span class="navbar-toggler-icon"></span>
       </button>
       <div class="collapse navbar-collapse" id="navbarSupportedContent">
           <ul class="navbar-nav navbar-left">{% if user.is_authenticated %}
               <li class="nav-item">
                   <a class="nav-link" href="#">All Posts</a>
               </li>
               <li class="nav-item">
                   <a class="nav-link" href="#">All Users</a>
               </li>
               <li class="nav-item">
                   <a class="nav-link" href="#">New post</a>
               </li>
               <li class="nav-item dropdown">
                   <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button"
                      data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                       {{ user.username }}'s detail
                   </a>
                   <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
                       <a class="dropdown-item" href="#">My posts</a>
                       <a class="dropdown-item" href="#">Following</a>
                       <a class="dropdown-item" href="#">Follower</a>
                   </div>
               </li>{% endif %}
           </ul>
           <ul class="navbar-nav navbar-right">{% if user.is_authenticated %}
               <li class="nav-item">{# {% url 'account_logout' %}は、Allauthの定型文 #}
                   <a class="nav-link" href="{% url 'account_logout' %}">Logout</a>
               </li>{% else %}
               <li class="nav-item">{# {% url 'account_login' %}は、Allauthの定型文 #}
                   <a class="nav-link" href="{% url 'account_login' %}">Login</a>
               </li>
               <li class="nav-item">{# {% url 'account_signup' %}は、Allauthの定型文 #}
                   <a class="nav-link" href="{% url 'account_signup' %}">Sign in</a>
               </li>{% endif %}
           </ul>
       </div>
   </nav>
</header>
{% block content %}
   <!-- ここに各htmlの内容が反映される -->
{% endblock content %}
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS,Fontawasome -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
       integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
       crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
       integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
       crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
       integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
       crossorigin="anonymous"></script>
<script defer src="https://use.fontawesome.com/releases/v5.7.2/js/all.js"></script>
{% block footer %}
{% endblock footer %}
</body>
</html>

 navbarhref属性リンクですが、allauthurlを使用しますのでログアウト、ログイン、ユーザー登録はそれぞれhref="{% url 'account_logout' %}"、href="{% url 'account_login' %}"、href="{% url 'account_signup' %}"となります。下の画像は、allauth/account/urls.pyのコードです。こちらでも、なぜそうなっているか確認できると思います。

           <ul class="navbar-nav navbar-right">{% if user.is_authenticated %}
               <li class="nav-item">{# {% url 'account_logout' %}は、Allauthの定型文 #}
                   <a class="nav-link" href="{% url 'account_logout' %}">Logout</a>
               </li>{% else %}
               <li class="nav-item">{# {% url 'account_login' %}は、Allauthの定型文 #}
                   <a class="nav-link" href="{% url 'account_login' %}">Login</a>
               </li>
               <li class="nav-item">{# {% url 'account_signup' %}は、Allauthの定型文 #}
                   <a class="nav-link" href="{% url 'account_signup' %}">Sign in</a>
               </li>{% endif %}
           </ul>
画像8

 ログイン画面、ユーザー登録画面にもbootstrapを適用していきます。テンプレートを保存するフォルダをtemplate/accountにしましたが、allauthの標準テンプレートを上書きするために設定しました。フォルダ名だけ間違えなければ、シンプルなページですのでコードのみ載せます。

 templates/account/login.html

{% extends 'base.html' %}
{% block content %}
   <div class="row">
       <div class="col-sm-6 offset-sm-3">
           <h1 >ログイン</h1>
           {#  ここ{% url 'account_login' %}は、Allauthを使う際の定型文#}
           <form method="POST" action="{% url 'account_login' %}">
               {% csrf_token %}
               {% bootstrap_form form %}
               <button type="submit" class="btn btn-primary" name="button">
                   ログイン
               </button>
           </form>
       </div>
   </div>
{% endblock %}

 templates/account/signup.html

{% extends 'base.html' %}
{% block content %}
   <div class="row">
       <div class="col-sm-6 offset-sm-3">
           <h1 class="mb-4">ユーザー登録</h1>
           {#  ここ{% url 'account_signup' %}は、Allauthを使う際の定型文#}
           <form method="POST" action="{% url 'account_signup' %}">
               {% csrf_token %}
               {% bootstrap_form form %}
               <button type="submit" class="btn btn-primary" name="button">
                   登録
               </button>
           </form>
       </div>
   </div>
{% endblock %}

 トップページを作成します。Homeviewと対応するhome.htmlを作成します。それぞれ、とてもシンプルですのでコードのみ載せます。

 accounts/views.py

from django.shortcuts import render
from django.views.generic.base import TemplateView
# Create your views here.
class HomeView(TemplateView):
   template_name = 'account/home.html'

 templates/account/home.html

{% extends 'base.html' %}
{% load bootstrap4 %}
{% block content %}
   <div class="center jumbotron">
       <div class="text-center">
           <h1>Welcome to the Microposts</h1>
           {#  ここ{% url 'account_signup' %}は、Allauthを使う際の定型文#}
           <a class="btn btn-outline-secondary btn-sm"
              href="{% url 'account_signup' %}"
              role="button">Sign in Now!</a>
       </div>
   </div>
{% endblock %}

 たったこれだけでallauthのログイン、ログアウト、サインアップの基本的な認証機能実装は完了です。拍子抜けするくらい簡単です。コードの量もallauthを使わない場合に比べて半分以下で済みます。
 ターミナルを立ち上げて動作を確認して見て下さい。自作のテンプレートはうまく表示されているでしょうか?ユーザーを登録してみて、データベースに反映されるかなども確認してみて下さい。

ユーザープロフィール更新の実装

 ユーザープロフィールについては、allauthで準備されていませんので自分で作成する必要があります。プロフィール更新ですので、CRUDのUpdateということでクラスベース汎用ビューのUpdateViewを使っていきます。accounts/views.pyを開いて下さい。
 コードの前半で必要なモジュールをインポートします。UpdateViewLoginRequiredMixin及びプロフィール更新に必要なフォームProfileForm(後ほど作成します)をインポートします。ユーザープロフィール画面のテンプレートは、edit_profile.htmlとし、使用するモデルはCustomUser、使用するフォームはProfileFormになります。更新完了後は、success_url= '/accounts /edit_profile/'として同じページを再度読み込みます。

 accounts/views.py

from django.views.generic.base import TemplateView
from django.views.generic.edit import UpdateView # 追加
from django.contrib.auth.mixins import LoginRequiredMixin # 追加
from .models import CustomUser 
from .forms import ProfileForm  # 追加

class HomeView(TemplateView):
   template_name = 'account/home.html'
   
class ProfileEditView(LoginRequiredMixin, UpdateView): # 追加
  template_name = 'account/edit_profile.html'
  model = CustomUser
  form_class = ProfileForm
  success_url = '/accounts/edit_profile/'
  def get_object(self):
      return self.request.user

 次は、ProfileFormforms.pyに設定します。ProfileFormforms.ModelFormを継承して作成します。def __init__(self, *args, **kwargs):では、bootstrapのform-controlが出来るように設定します。次に、Class Metaとして、フォームのフィールドを設定します。使用するモデルは、CustomUser、ユーザー情報として更新したいフィールドをnickname, email, avatarとします。help_texts ={ }では、それぞれのフィールドの補足を加えられます。ここでは、nicknameの補足としてユーザーネームと表示されるようにしています。好みで設定を加えて見て下さい。

 accounts/forms.py

from django import forms
from .models import CustomUser

class ProfileForm(forms.ModelForm):
   def __init__(self, *args, **kwargs):
       super(ProfileForm, self).__init__(*args, **kwargs)
       for field in self.fields.values():  # bootstrapで使用するform-controlクラス
           field.widget.attrs['class'] = 'form-control'
           
   class Meta:
       model = CustomUser
       fields = ('nickname', 'email', 'avatar')
       help_texts = {
           'nickname': "ユーザーネーム",
           'email': None,
       }

urls.pyでパスを通します。名前空間は、name='edit_profile'と設定します。

accounts/urls.py

from django.urls import path
from .views import HomeView, ProfileEditView  # 追加
app_name = 'accounts'
urlpatterns = [
   path('home/', HomeView.as_view(), name='home'),
   path('edit_profile/', ProfileEditView.as_view(), name='edit_profile'),  # 追加
]

対応するテンプレートを作成します。こちらも、他のテンプレートとあまり変わりません。画像ファイルをアップロードするためには、<form>タグ内で、enctype="multipart/form-data"を指定しなければいけません。これを設定しないと、画像がアップロード出来ません。ご興味があれば、enctypeを外して試して見て下さい。

account/edit_profile.html

{% extends 'base.html' %}
{% block content %}
   <div class="content-wrapper">
       <div class="container-fluid">
           <div class="row">
               <div class="col-sm-6 offset-sm-3">
                   <div class="card">
                       <div class="card-header">
                           <h4><b>プロフィール更新</b></h4>
                       </div>
                       <div class="card-body">
                           {# 画像ファイルをアップロードするためenctype="multipart/form-data"を指定#}
                           <form action="{% url 'accounts:edit_profile' %}" method="post"
                                 enctype="multipart/form-data">
                               {% csrf_token %}
                               {% bootstrap_form form %}
                               <button class='btn btn-outline-success btn-block' type="submit">更新</button>
                           </form>
                       </div>
                   </div>
               </div>
           </div>
       </div>
   </div>
{% endblock %}

ターミナルからサーバーを立ち上げhttp://127.0.0.1:8000/accounts/ edit_profile/へアクセスして動作を確認して見て下さい。LoginRequiredMixinを設定していますので、ログインしていない状態ではアクセスできないと思います。下の画像のように、ニックネームや画像登録などが出来ましたでしょうか?

プロフィール更新
プロフィール更新2

このようにallauthを用いると非常に簡単に基本的な認証を実装できます。また、googleやFaceBookなどのSNS認証にも対応していますので、SNS認証をdjangoに実装したい場合にもallauthは有効です。


ソースコードは、Githubに載せておりますのでそちらも参照ください。

この記事が気に入ったらサポートをしてみませんか?