【Django入門9】カスタムユーザーによるユーザー管理

このページにはプロモーションが含まれています

このページでは、Django における『カスタムユーザー』について解説していきます。

カスタムユーザー を導入することで、以降で解説する『ログイン機能』をウェブアプリで簡単に実現することができるようになります。

この Django 入門 の連載では、連載を通して掲示板アプリを開発していっています。この掲示板アプリでも User というモデルクラスを定義していますが、この User では、ユーザー名・メールアドレス・年齢の3つのフィールドのみを扱うようになっています。

今までの掲示板アプリで使用してきたUser

この掲示板アプリは Django 入門者の方向けに、学習用に作成しているウェブアプリなので、上記のような User でユーザーを管理するのでも問題ないのですが、本格的なウェブアプリを開発してい行く上では、ユーザーを管理するモデルクラスとしては上記のような User では不十分です。

例えば、ウェブアプリにはログイン機能を備えたものが多いです。ログインは、ユーザーに設定されたパスワードに基づいて実施されるため、ユーザーを管理するモデルにはパスワード管理機能が必要となります。また、ユーザーに応じて利用可能な機能を制限するため、ユーザーに権限を設定できるよう、権限管理機能も備えておく必要があります。

こういった、ウェブアプリを開発していく上で必要となるユーザー管理モデルを実現するためのモデルクラスが、今回紹介する カスタムユーザー になります。

多機能なウェブアプリを開発していく上で必要となるユーザー管理モデルのフィールド

今回、この カスタムユーザーAbstractUser というクラスから作成することを前提に解説を進めます。他にも AbstractBaseUser というクラスから作成することもでき、それに関しては下記ページで解説していますので、こちらについて知りたい方は別途下記ページをご参照いただければと思います。

カスタムユーザーをAbstractBaseUserを継承して作成する手順の解説ページアイキャッチ 【Django】カスタムユーザー(独自のユーザー)の作り方【AbstractBaseUser編】

また、このページは Django 入門 の連載を読み進めてきていただいた方向けの解説を行います。連載とは分離する形で、個別にカスタムユーザーのみについて解説するページも下記に用意していますので、カスタムユーザーについてのみ知りたい方は、下記ページの方を読んでいただくことをオススメします。

【Django】カスタムユーザー(独自のユーザー)の作り方【AbstractUser編】

カスタムユーザー の基本

では、ここから、カスタムユーザー の基本的な事柄について解説していきます。

カスタムユーザー とは

カスタムユーザー とは、ユーザーを管理するモデルの1つで、Django フレームワークで定義される AbstractUser というモデルクラスを継承し、ウェブアプリに合わせてカスタマイズしたクラスのことを言います。

カスタムユーザーの説明図

この AbstractUser は、下の図のように AbstractBaseUserPermissionsMixin を継承するクラスで、簡単に言えば、AbstractBaseUser はパスワードに関する基本的な機能を備えたクラス、PermissionsMixin は権限に関する基本的な機能を備えたクラスになります。

AbstractUserの継承関係を示す図

なので、これらを継承する AbstractUser は、パスワードや権限に関する基本的な機能を備えたクラスとなります。そして、この AbstractUser を継承して カスタムユーザー を定義することになるため、カスタムユーザー に関してもパスワードや権限に関する基本的な機能を備えたクラスとなります。

分かりやすい例で言えば、パスワード管理は、ウェブアプリでのログインを実現するために必要となる機能です。そして、カスタムユーザー は、このパスワードの管理機能を備えていますので、カスタムユーザー を利用することで簡単にログインを実現することができるようになります。権限に関しては、例えば管理画面へのログインの可否や管理画面での各種操作の利用の可否を判断するために用いられます。

特に権限に関しては、下記ページの管理画面での解説の中で詳細を解説しようと思います。

Djangoの管理画面の使い方の解説ページアイキャッチ 【Django入門11】管理画面(admin)の使い方の基本

また、AbstractUserusername (ユーザー名) や password (パスワード) など、ユーザーを管理する上で必要となる基本的なフィールドも保持しています。なので、AbstractUser を継承することで、カスタムユーザー でも、これらのフィールドを利用することが可能です。

こんな感じで、カスタムユーザー とは、ユーザーを管理する上で必要となる基本的な機能やフィールド等を持つクラスとなります。ただし、AbstractUser には、一般的なウェブアプリで必要となる共通的な機能やフィールド・メソッドしか定義されていません。そのため、カスタムユーザーAbstractUser を単に継承するだけでなく、開発するウェブアプリで扱うユーザーに合わせたカスタマイズが必要となります。例えばフィールドを追加したりメソッドを追加したりすることが必要です。このあたりは後述で解説していきたいと思います。

スポンサーリンク

カスタムユーザー はモデルクラスの一種

また、AbstractUserAbstractBaseUserModel のサブクラスの1つとなります。なので、これらを継承する カスタムユーザーModel のサブクラスであり、下記ページで解説しているモデルクラスであることになります。

モデルの解説ページアイキャッチ 【Django入門6】モデルの基本

カスタムユーザー クラスはテーブル

したがって、カスタムユーザー は、上記のようなパスワードや権限に関する機能だけでなく、データベースの操作機能も持っています。

また、モデルクラスはデータベースのテーブルに、そして、モデルクラスのインスタンスはレコードに相当するため、カスタムユーザー クラスは「ユーザーを管理するためのテーブル」で、カスタムユーザー のインスタンスは「そのテーブルのレコード」として扱うことができます。さらに、このレコードにはユーザーの情報がセットされていますので、インスタンスをユーザーそのもののように扱うことができます。

カスタムユーザーのクラスがテーブル、インスタンスがレコード(ユーザーそのもの)として扱われることを示す図

このように、カスタムユーザー は、通常のモデルクラスと同じような使い方も可能であることは覚えておくとよいと思います。

ModelModel のサブクラス との違い

ここで、少し話は逸れますが、ModelAbstractUser のような Model のサブクラス との違いについて解説しておきます。

Model は、(作り込むことで)どんなデータでも管理できるように定義された超抽象的なクラスになります。なので、もちろん Model を継承したクラスでユーザーを管理することも可能です。ですが、その管理対象に合わせたカスタマイズ(フィールドやメソッド等の追加)が別途必要になります。

Modelと、Modelのサブクラスとの違いを説明する図1

これに対し、Model のサブクラス は、何らかのデータを管理できるように特化されており、そのデータを管理できるように既にカスタマイズされたクラスになります。なので、ウェブアプリで管理したいデータに特化した Model のサブクラス が存在するのであれば、それを継承してクラスを定義した方が楽に目的のクラスを実現できることになります。

前述の通り、AbstractUser はユーザーを管理することに特化した Model のサブクラス ですので、ユーザーを管理するモデルクラスを定義するのであれば、Model を継承するのではなく、AbstractUser を継承する方が良いです。AbstractUser の場合は、継承するだけでユーザーを管理するモデルクラスが実現できます。

Modelと、Modelのサブクラスとの違いを説明する図2

User クラスとの使い分け

実は、Django フレームワークでは AbstractUserAbstractBaseUser だけでなく、User というクラスも定義されています。そして、この UserAbstractUser を継承するクラスになります。したがって、この User にもパスワードや権限に関する機能が備えられていることになります。

MEMO

この User は、ページの最初に紹介した掲示板アプリの User とな異なるクラスとなります

なので、ユーザーを管理するモデルクラスとして、この User を使用するというのも1つの手になると思います。

ただ、この User は「一般的なウェブアプリ向けのユーザー」として既に完成しているモデルクラスとして扱われることが多いです。なので、User を利用するのであれば、カスタマイズ等を行わずにそのまま使うのが一般的です。

逆に、開発するウェブアプリ向けにカスタマイズを行うのであれば、カスタムユーザー を別途定義し、その カスタムユーザー をユーザーを管理するモデルクラスとして利用することが推奨されています。そして、ユーザー管理モデルが持つフィールドや機能等はウェブアプリの特徴に直結することも多いため、カスタマイズが必要になることを考慮して User は利用せず、カスタムユーザー を利用するのが良いと思います。

もちろん、お試しでウェブアプリを開発する場合などは User を利用するのでも良いです。

カスタムユーザー の作り方

続いて、カスタムユーザー の作り方(定義の仕方)について解説していきます。

前述のとおり、カスタムユーザー はモデルクラスであるため、通常のモデルクラスと同様に models.py に定義を行うことになります。

スポンサーリンク

AbstractUser を継承する

また、これも前述のとおり、カスタムユーザーAbstractUser のサブクラスとして定義します。

この AbstractUserdjango.contrib.auth.models で定義されているため、models.py を下記のように実装すれば、カスタムユーザー である CustomUser が定義できることになります。

AbstractUserの継承
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    pass

非常に簡単な定義になりますが、これでも CustomUser には、パスワードや権限に関連する機能やユーザーに関するフィールドが備えられており、ユーザーを管理するための基本的な機能の備わったモデルクラスとして扱うことができます。

また、上記のように定義した CustomUser は前述で示した User と機能的には同等のモデルクラスとなります。

プロジェクトで使用する「ユーザー管理モデル」に設定する

カスタムユーザー を定義したら、次はプロジェクトで使用する「ユーザー管理モデル」として、定義した カスタムユーザー を設定する必要があります。

プロジェクトの「ユーザー管理モデル」とは

Django では、プロジェクト(ウェブアプリ)で使用する「ユーザー管理モデル」を設定できるようになっています。例えば、管理画面にログインするときには、このユーザー管理モデルとして設定されているモデルクラスのテーブルが参照されますし、後述で紹介するコマンドでのユーザー作成時には、このユーザー管理モデルとして設定されているモデルクラスのインスタンスが生成されるようになっています。

ユーザー管理モデルのテーブルが認証やコマンドによるユーザー作成時に利用される様子

そして、デフォルトでは、プロジェクトで使用するユーザー管理モデルとして User クラスとの使い分け で紹介した User が設定されています。新たに定義した カスタムユーザー がプロジェクトで使用されるようにするためには、この設定を変更する必要があります。

プロジェクトで使用する「ユーザー管理モデル」の設定方法

プロジェクトで使用するユーザー管理モデルに カスタムユーザー を設定するためには、プロジェクトの settings.pyAUTH_USER_MODEL の設定を追記する必要があります(ファイルの一番下に追記するので問題ありません)。

AUTH_USER_MODELの設定
AUTH_USER_MODEL = 'アプリ名.カスタムユーザー名'

アプリ名 には、カスタムユーザー を定義した models.py が所属するアプリの名前を、カスタムユーザー名 には カスタムユーザー のクラス名を指定します。例えば、アプリの名前が forum で、カスタムユーザー のクラス名が CustomUser であるのであれば、プロジェクトの settings.py に下記を追記すればよいことになります。

AUTH_USER_MODELの設定例
AUTH_USER_MODEL = 'forum.CustomUser'

カスタムユーザー を定義したにもかかわらず、上記のような設定を行わなかった場合、マイグレーション実行時に次のような例外が発生することになるので注意してください。

ERRORS:
auth.User.groups: (fields.E304) Reverse accessor 'Group.user_set' for 'auth.User.groups' clashes with reverse accessor for 'forum.CustomUser.groups'.
        HINT: Add or change a related_name argument to the definition for 'auth.User.groups' or 'forum.CustomUser.groups'.
~略~

これは、リレーション設定用のフィールド追加時に指定する related_name の値が UserCustomUser で重複しているという例外になります。UserCustomUser の両方に対してマイグレーションが行われると上記のような例外が発生することになり、User に対してマイグレーションが行われるのは AUTH_USER_MODELUser が指定されているからになります。

なので、AUTH_USER_MODELUser 以外を指定してやれば、User に対するマイグレーションが行われなくなり、この例外も発生しなくなります。

MEMO

逆に、ユーザー管理モデルを User のままにするのであれば、カスタムユーザー は定義してはいけないということになります

ということで、カスタムユーザー を定義したら、settings.py への AUTH_USER_MODEL の設定の追記を忘れないようにしましょう。

また、以降では、プロジェクトで使用するユーザー管理モデルのことを、単に AUTH_USER_MODEL と記します。

フィールド・メソッドを追加する

AbstractUser のサブクラスとして カスタムユーザー を定義し、さらに AUTH_USER_MODEL の設定が完了すれば、後は必要に応じて開発するウェブアプリ向けに カスタムユーザー のカスタマイズを行っていけば良いだけになります。

このカスタマイズで行うことの1つは、AbstractUser に不足しているフィールドの追加・メソッドの追加になります。そして、このフィールドの追加に関しては通常のモデルクラス同様のやり方で、メソッドの追加に関しては一般的なクラス同様のやり方で実現できます。

例えば、先ほど定義した CustomUserage フィールドと、そのユーザーが未成年であるかどうかを判断する is_minor メソッドを追加する例は下記のようになります。

フィールドの追加・メソッドの追加
from django.db import models
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    age = models.IntegerField()

    def is_minor(self):
        return True if self.age >= 18 else False

もちろん、フィールドの追加によってリレーションを設定したり、バリデーターを設定したりすることも可能です。前述のとおり、カスタムユーザー はモデルクラスなので、モデルクラスで実現できることは カスタムユーザー でも実現可能です。

また、メソッドのオーバーライドも可能なのですが、基本的にはユーザー管理を実現するために必要なメソッドばかりなので、オーバーライドを行う機会は少ないですし、やるとしても AbstractUser の作りをしっかり理解してからの方が良いと思います。

参考:カスタムユーザー の持つフィールド

参考に、カスタムユーザー がデフォルトで持つフィールド、すなわち AbstractUser の持つフィールドをまとめた表を下記に示しておきます。ウェブアプリを開発するために、下記に足りないフィールドがあるのであれば、それをフィールドとして定義して追加してやれば良いことになります。

フィールド名 役割
id ID (プライマリーキー)
password パスワード
last_login 最終ログイン日時
is_superuser スーパーユーザーであるか否か
username ユーザー名
first_name ファーストネーム
last_name ラストネーム
email メールアドレス
is_staff 管理スタッフであるか否か
is_active アクティブユーザーであるか否か
date_join ユーザー作成日時
groups ユーザーが所属するグループ
user_permissions ユーザーの持つ権限

スポンサーリンク

特殊フィールドの設定を行う

また、必要に応じて、特殊フィールドの設定を行うことも可能です。

AbstractUser においては、下記の3つのクラス変数が定義されており、これらのクラス変数に指定されているフィールドは、少し特殊な意味を持つフィールドとして扱われます。

  • USERNAME_FIELD
  • EMAIL_FIELD
  • REQUIRED_FIELDS

具体的には、 USERNAME_FIELD に指定されたフィールドは『ユーザーを識別するフィールド』、EMAIL_FIELD に指定されたフィールドは『メールアドレスとして扱うフィールド』を 、REQUIRED_FIELDS に指定されたフィールドは『入力受付を必須とするフィールド』として扱われることになります。

そして、AbstractUser では、これらのクラス変数は下記のように定義されています。

各種フィールドのデフォルト設定
EMAIL_FIELD = "email"
USERNAME_FIELD = "username"
REQUIRED_FIELDS = ["email"]

AbstractUser を継承する カスタムユーザー においても上記のクラス変数が引き継がれることになりますが、カスタムユーザー 側でクラス変数を再定義することで、これらのクラス変数に指定するフィールドを変更することが可能で、これにより カスタムユーザー のカスタマイズを行うことができます。

特に、変更する機会が多いのは USERNAME_FIELDREQUIRED_FIELDS になりますので、この2つについてクラス変数の意味合いや変更例等についての詳細を解説していきます。

USERNAME_FIELD

USERNAME_FIELD は『ユーザーを識別するフィールド』を設定するクラス変数で、この『ユーザーを識別するフィールド』とは、主にログイン等で使用する、パスワードとは異なる方のフィールドのことになります。

USERNAME_FIELDの意味合いを示す図

ウェブアプリでは、ログイン時にパスワードだけでなく、『ユーザーを識別するフィールド』の入力が必要です。『ユーザーを識別するフィールド』 はウェブアプリによって違っていて、ユーザー名を入力してログインを行うウェブアプリもありますし、メールアドレスを入力してログインを行うウェブアプリもあります。

このように、ウェブアプリによって『ユーザーを識別するフィールド』として使用するフィールドは異なることになり、カスタムユーザー において、この『ユーザーを識別するフィールド』の設定を行うためのクラス変数が USERNAME_FIELD となります。

また、USERNAME_FIELD で設定するフィールドは、上記のようにログイン時に入力するフィールドとしても利用されますし、カスタムユーザー のインスタンスを出力したときに表示されるデータも、この USERNAME_FIELD で指定されたフィールドの値となります。つまり、__str__ メソッドの返却値は、この USERNAME_FIELD に指定されたフィールドの値ということになります。

__str__ メソッドに関しては下記ページで解説していますので、詳しく知りたい方は別途下記ページを参照してください。

モデルの__str__メソッドの説明ページアイキャッチ 【Django】モデル(Model)の__str__メソッドとは?

USERNAME_FIELD にはデフォルトで "username" が設定されていますので、ログイン時に入力受付を行うフィールドや、インスタンス出力時に表示されるフィールドを username 以外のものに変更したいのであれば、USERNAME_FIELD の変更を行う必要があります。

そして、この USERNAME_FIELD は、カスタムユーザー で USERNAME_FIELD を定義することで変更することが可能です。例えば、下記のように カスタムユーザーUSERNAME_FIELD を定義すれば nickname でログインできるようになりますし、インスタンスの出力結果が nickname の値に変化することになります。

USERNAME_FIELDの定義例
from django.db import models
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    nickname = models.CharField(max_length=32, unique=True)

    USERNAME_FIELD = 'nickname'

ただし、USERNAME_FIELD に設定するフィールドには unique=True が設定されている必要があるので注意してください。具体的には、これに設定するフィールドを定義するときに実行する Field のサブクラスのコンストラクタに引数 unique=True を設定しておく必要があります。この unique=True は、そのフィールドの値が他のレコードと重複することを禁止するための設定となります。

REQUIRED_FIELDS

REQUIRED_FIELDS は『入力受付を必須とするフィールド』を設定するクラス変数です。

この設定は、コマンドでのユーザー作成時(カスタムユーザー のインスタンス作成時)に参照される設定になります。Django のコマンドには createsuperuser が存在し、このコマンドを実行して必要なフィールドの情報を入力すれば “スーパーユーザー” を作成することができます。で、このコマンドで入力受付されるフィールドは下記の3種類のものになります

  • USERNAME_FIELD で指定されたフィールド
  • REQUIRED_FIELDS で指定されたフィールド群
  • password (確認用のパスワードの入力受付も行われる)

上記のように REQUIRED_FIELDS が参照されるので、REQUIRED_FIELDS を変更することで、コマンドでのユーザー作成時に入力受付するフィールドを変更することができます。

ポイントは、カスタムユーザー に追加した “必須フィールド” も、コマンドでのユーザー作成時に入力受付する必要があるという点になります。

モデルクラスに持たせたフィールドは、そのフィールドに null=True オプションを指定しないと必須フィールドとして扱われることになります(必須フィールドとは、より具体的には、テーブルに保存する際に空であってはならないフィールドのことを指しています)。

たとえば、下記の CustomUser では age フィールドを追加しており、このフィールドは null=True オプションが指定されていないため、必須フィールドとして扱われます。必須フィールドに値が設定されていないインスタンスでは、テーブル保存時に例外が発生することになります。

CustomUser
from django.db import models
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    age = models.IntegerField()

実際に、この age フィールドに値を設定していないインスタンスをテーブルに保存しようとすると、下記のような例外が発生することになります。

django.db.utils.IntegrityError: NOT NULL constraint failed: forum_customuser.age

なので、こういった必須フィールドを カスタムユーザー に追加するのであれば、そのフィールドの値をフォームから送信できるようにフォームクラスを定義する必要がありますし、同様に、コマンドでユーザーを作成する際にも、必須フィールドの値を指定できるようにする必要があります。

そして、特にコマンドでユーザーを作成する際には REQUIRED_FIELDS に含めたフィールドの入力受付が行われることになりますので、REQUIRED_FIELDSカスタムユーザー の必須フィールドを全て指定する必要があります。もしくは、カスタムユーザー の必須フィールドを「非必須フィールド」に変更する (null=True オプションを追加する) or 必須フィールドのデフォルト値を指定しておく必要があります。

例えば、先ほど示した CustomUser の例であれば、コマンドでのユーザー作成を行えるようにするためには下記のように REQUIRED_FIELDS の定義を追加してやれば良いことになります。

REQUIRED_FIELDSの定義例
from django.db import models
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    age = models.IntegerField()

    REQUIRED_FIELDS = ['email', 'age']

もしくは、下記のように age フィールドに null=True オプションを指定し、age フィールドの値が指定されていない状態でもテーブルへの保存が行えるようにすることで、コマンドでのユーザー作成を実現することもできます。

null=Trueオプションの追加
from django.db import models
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    age = models.IntegerField(null=True)

REQUIRED_FIELDSAbstractUser のフィールドに合わせて設定されていますので、カスタムユーザー 側でフィールドを追加した場合は、REQUIRED_FIELDS の見直し・変更が必要となります。

また、REQUIRED_FIELDS には USERNAME_FIELD に指定したフィールドは含められないので注意してください。

カスタムユーザー の使い方

続いて、カスタムユーザー の使い方について説明していきます。

基本的な使い方は他のモデルクラスと同じ

カスタムユーザー はモデルクラスの一種なので、基本的には他のモデルクラスと同じようにビューやテンプレートファイルから扱うことが可能です。特に、データベース関連の操作は、他のモデルクラスとほぼ同じと考えて良いです。このあたりに関しては、後述の 掲示板アプリでカスタムユーザーを利用してみる で実例で確認していきたいと思います。

あとは、カスタムユーザー に追加したフィールドやメソッドを上手く使ってビューで機能を実現していけばよいことになります。

ただ、カスタムユーザー ならではの使い方も存在しますので、このあたりについて、ここから解説していきたいと思います。

スポンサーリンク

カスタムユーザーget_user_model で取得する

Django フレームワークの django.contrib.auth には get_user_model という関数が定義されており、この関数を実行することで AUTH_USER_MODEL のクラスオブジェクトを返却値として取得することができるようになっています。

プロジェクトで使用する「ユーザー管理モデル」に設定する で解説したように、この AUTH_USER_MODEL には、カスタムユーザー を定義している場合は カスタムユーザー を設定しているはずなので、要は get_user_model を実行することで カスタムユーザー のクラスオブジェクトを取得することができるということになります。

そして、views.pyforms.py 等から get_user_model を実行して カスタムユーザー のクラスオブジェクトを取得し、このオブジェクトからテーブル操作を行ったり、インスタンスを生成したりすることが可能となります。

例えば、下記は views.pyget_user_model を実行し、それによって得られたオブジェクトから カスタムユーザー のテーブルの全レコードを取得する例になります。

get_user_modelの利用例
from django.contrib.auth import get_user_model
from django.shortcuts import render, get_object_or_404

# カスタムユーザーを取得
User = get_user_model()

def users_view(request):
    users = User.objects.all()

    context = {
        'users' : users
    }

    return render(request, 'テンプレートファイルのパス', context)

もちろん、get_user_model を使用せず、他のモデルクラスと同様に、models.py から カスタムユーザーimport して使用するのでも良いです。ですが、get_user_model を利用した方がウェブアプリのメンテナンス性が高くなります。

具体的にいうと、get_user_model を利用した場合、後で カスタムユーザー のクラス名を変更した場合に修正が必要となる箇所は settings.py の AUTH_USER_MODEL 設定箇所のみとなります。

get_user_modelを利用している場合に、後からカスタムユーザーの名前を変更したときに修正が必要になる箇所

ですが、models.py から カスタムユーザーimport して使用していた場合、カスタムユーザー のクラス名を変更した際には、その import を行っている個所の全てを修正する必要がありますし、変更前の カスタムユーザー のクラス名を記述している個所も全て修正が必要になります。特に、ユーザー管理用のモデルクラスは様々なモジュールから利用されることになるため、この場合は修正が非常に大変になりますし、修正漏れがあるとバグになります。

get_user_modelを利用していない場合に、後からカスタムユーザーの名前を変更したときに修正が必要になる箇所

そのため、メンテナンス性の高いウェブアプリを開発していく上では、AUTH_USER_MODEL、すなわち カスタムユーザー は、 get_user_model から取得して使用するようにした方が良いです。

カスタムユーザー をベースにフォームを定義する

また、前述のとおり、カスタムユーザー は他のモデルクラスと同様に利用することができ、下記ページで解説しているモデルフォームクラスのベースとして指定することも可能です(model 属性に指定可能)。また、モデルフォームクラスは、ModelForm クラスを継承することで定義することが可能です。

Djangoのモデルフォーム解説ページアイキャッチ 【Django入門8】モデルフォームの基本

なんですが、カスタムユーザー を作成するモデルフォームクラスを定義する際には、ModelForm クラスを継承するのではなく、UserCreationForm を継承することをオススメします。

UserCreationForm とは

UserCreationFormModelForm のサブクラスであり、UserCreationForm を継承するクラスも通常のモデルフォームクラスと同様にして定義することができます。

より具体的には、UserCreationForm のサブクラスとして定義し、model 属性でベースとするモデルクラスを、fields 属性(or exclude 属性)でフォームに持たせるフィールドを指定してクラスを定義することになります。で、カスタムユーザー を作成するフォームとするために、model 属性には カスタムユーザー を指定することになります。

UserCreationFormのサブクラスの定義の仕方を示す図

ただ、ModelForm を継承したクラスによって実現されるフォームに比べ、UserCreationForm を継承したクラスによって実現されるフォームには下記の違いがあります。

  • パスワードフィールド(確認用パスワードも含めて)が自動的に追加される
  • パスワードフィールドへの入力文字は伏字になる
  • パスワードフィールドへ入力されたパスワードは、暗号化してデータベースに保存される

UserCreationForm を継承するメリット

最も重要なのは最後の1つで UserCreationForm を継承することで、パスワードを暗号化したデータ(ハッシュ化されたデータ)で扱うことができるようになります。ModelForm においても、パスワードフィールドを追加するようクラスを定義すればパスワードの入力自体は受け付けることができるようになります。ですが、基本的には、そのフィールドに入力されたパスワードは平文で扱われることになり、データベースにも平文で保存されることになります。

ModelFormを継承するクラスとUserCreationFormを継承するクラスとの保存されるパスワードの違い

したがって、もしデータベースの中身を他の人に見られたら、ユーザーのパスワードが流出することになります。こうなるとニュースで取りあげられるくらい大問題になります…。自力で暗号化を行うようなウェブアプリを開発するという手もありますが、暗号に関する深い知識も必要になりますし、上手く作らないと、結局パスワードの流出のような問題が発生する可能性があります。

ModelFormでパスワードを扱うとパスワード流出の可能性があることを示す図

それに対し、UserCreationForm を継承したクラスの場合、パスワードフィールドへ入力されたパスワードが暗号化され、暗号化された状態でデータベースに保存されることになります。なので、たとえデータベースの中身が見られたとしても、理論的には暗号化前のパスワードが流出することはありません。つまり、UserCreationForm を継承したクラスを利用するだけで、安心してパスワードを扱うことのできるウェブアプリが実現できます。

UserCreationFormでパスワードを扱うとパスワードが暗号化されて流出の可能性が下がることを示す図

ウェブアプリではパスワードは暗号化した状態で扱うというのが大前提になります。なので、パスワードの入力受付を行うフォームを作るのであれば、必ず UserCreationForm のようなパスワードを暗号化してくれるクラスを利用した方が良いです。

ということで、カスタムユーザー でパスワードを扱うのであれば、必ずユーザー作成用のフォームは UserCreationForm を継承して定義するようにしましょう。 

また、こういった、暗号化のような難しい技術も簡単に利用できるという点は、Django を含むフレームワークを利用する大きなメリットだと言えます。

UserCreationForm を継承したフォームの定義例

UserCreationForm を継承する カスタムユーザー 作成用のモデルフォームクラスの定義例は下記のようになります。

カスタムユーザー作成フォーム
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm

User = get_user_model()

class CreateUserForm(UserCreationForm):
    class Meta:
        model = User
        fields = [User.USERNAME_FIELD] + User.REQUIRED_FIELDS

fields = [User.USERNAME_FIELD] + User.REQUIRED_FIELDS を指定しておくことで、カスタムユーザー の持つフィールドの中の “入力受付が必須となるフィールド” を全て含むモデルフォームクラスが定義できることになります(カスタムユーザー の定義で、USERNAME_FIELDREQUIRED_FIELDS を適切に設定しておく必要があります)。

また、上記の Userget_user_model 関数の返却値なので カスタムユーザー を指すクラスオブジェクトということになります。

上記のように定義を行えば、入力受付が必須となるフィールドを全て含む カスタムユーザー 作成用のフォームが定義できることになりますので、まずは カスタムユーザー を作成するフォームは、上記の CreateUserForm と同じ形式で定義してやれば良いと思います。その後に、必要に応じてカスタマイズを行っていけばよいです。 

ちなみに、上記の CreateUserForm をテンプレートファイルに埋め込むことで表示されるフォームは下図のようなものになります(スタイル等の設定を行うことで、もっと見た目を良くすることは可能です)。

UserCreationFormの表示例

createsuperuser コマンドでのユーザーを作成する

特殊フィールドの設定を行う でも少し説明しましたが、Django には createsuperuser コマンドが存在し、このコマンドで、ウェブアプリのスーパーユーザーを作成することができます。スーパーユーザーとは、簡単に言えば全ての管理権限を持ったユーザーです。

管理画面については別途下記ページで解説を行いますが、管理画面とはウェブアプリで扱う各種テーブルのレコードの管理を行う画面であり、この管理画面にログイン可能なユーザーを作成するときに、この createsuperuser コマンドを利用することが多いです。

Djangoの管理画面の使い方の解説ページアイキャッチ 【Django入門11】管理画面(admin)の使い方の基本

で、この createsuperuser コマンドを実行した際には カスタムユーザー のインスタンスが生成されることになります。もう少し厳密に言うと、settings.py の AUTH_USER_MODEL に設定されたモデルクラスのインスタンスが生成されることになります。

なので、カスタムユーザー はフォーム等から作成するだけでなく、コマンドでも作成できることになります。具体的には、下記のように manage.py を利用して createsuperuser コマンドを実行し、”各種フィールド” の値を入力してやれば カスタムユーザー のインスタンスが生成され、データベースの カスタムユーザー のテーブルに保存されることになります。

python manage.py createsuperuser

また、上記の “各種フィールド” とは、特殊フィールドの設定を行う でも説明した下記の3種類のフィールドとなります。

  • USERNAME_FIELD で指定されたフィールド
  • REQUIRED_FIELDS で指定されたフィールド群
  • password (確認用のパスワードの入力受付も行われる)

そして、これも 特殊フィールドの設定を行う で説明した通り、カスタムユーザー における必須フィールドが全て入力できるように REQUIRED_FIELDS を定義しておくことが重要となります。

ここで説明しておきたいのは、今までは models.py で定義したモデルクラスは基本的にプロジェクト内のファイル(views.pyforms.py・テンプレートファイル等)のみからしか使用されていませんでしたが、カスタムユーザー は、それ以外のファイル、すなわち Django フレームワークからも利用されることになるという点になります。そして、その1つの例が、上記における createsuperuser コマンドからの カスタムユーザー の利用になります。

したがって、Django フレームワークからの使われ方も意識して カスタムユーザー を定義する必要があります。カスタムユーザー の定義が、Django フレームワークからの使われ方に適合していない場合は例外が発生するはずなので、その例外の内容に合わせて カスタムユーザー を修正する必要があります。

スポンサーリンク

掲示板アプリでカスタムユーザーを利用してみる

では、いつも通り、ここまで説明してきた内容を踏まえて、実際に カスタムユーザー の利用例を示していきたいと思います。

この Django 入門 に関しては連載形式となっており、ここでは前回下記ページの 掲示板アプリでモデルフォームを利用してみる で作成したウェブアプリに対して カスタムユーザー を導入する形で、カスタムユーザー の利用例を示していきたいと思います。

Djangoのモデルフォーム解説ページアイキャッチ 【Django入門8】モデルフォームの基本

カスタムユーザー を定義することで、ウェブアプリ内でパスワード管理や権限関連の機能を備えたユーザーを使用することができるようになります。ただ、今回は単に カスタムユーザー を導入するだけなので、特にこれらのフィールドや機能は意味を持ちません。

ですが、次回の連載でログイン機能について説明を行い、そこで カスタムユーザー を利用したログインの実装を行っていくことになります。そして、そこでは カスタムユーザー のパスワード管理機能が活躍することになります。なので、今回は、次回の説明に向けた準備と考え、まずは カスタムユーザー について理解を深めていただければと思います。

掲示板アプリのプロジェクト一式の公開先

この Django 入門 の連載を通して開発している掲示板アプリのプロジェクトは GitHub の下記レポジトリで公開しています。

https://github.com/da-eu/django-introduction

また、前述のとおり、ここでは前回の連載の 掲示板アプリでモデルフォームを利用してみる で作成したプロジェクトをベースに変更を加えていきます。このベースとなるプロジェクトは下記のリリースで公開していますので、必要に応じてこちらからプロジェクト一式を取得してください。

https://github.com/da-eu/django-introduction/releases/tag/django-modelform

さらに、ここから説明していく内容の変更を加えたプロジェクトも下記のリリースで公開しています。ソースコードの変更等を行うのが面倒な場合など、必要に応じて下記からプロジェクト一式を取得してください。

https://github.com/da-eu/django-introduction/releases/tag/django-customuser

カスタムユーザー の定義

では、早速 カスタムユーザー を定義していきたいと思います。

これまでの掲示板アプリにおいては、単なるモデルクラスとして下記の User を定義していました。

Userクラス
class User(models.Model):
    username = models.CharField(max_length=32, validators=[check_username])
    email = models.EmailField()
    age = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(200)])
    
    def __str__(self):
        return self.username

今回は、この User を削除し、代わりに カスタムユーザー として CustomUser クラスを定義していきたいと思います。ただし、もともとの User の持っていたフィールド usernameemailage は CustomUser にも持たせるようにしたいと思います。

このような CustomUser は、下記のように models.py を変更することで定義することができます(Comment に関しては、ForeignKey の第1引数の User から CustomUser への変更のみを行っています)。

models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.core.validators import MinValueValidator, MaxValueValidator

class CustomUser(AbstractUser):
    age = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(200)])

    REQUIRED_FIELDS = ['email', 'age']


class Comment(models.Model):
    text = models.CharField(max_length=256)
    date = models.DateTimeField(auto_now_add=True)
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, null=True, related_name='comments')

    def __str__(self):
        return self.text[:10]

参考:カスタムユーザー の持つフィールド で示したように、AbstractUser には usernameemail が存在し、それらは  CustomUser にも引き継がれることになるため、CustomUser では usernameemail の定義は不要になります。上記のように models.py を変更すると、もともとの User の username に対して実施されていた妥当性の検証が行われなくなってしまいますが、AbstractUserusername に対しても妥当性の検証が行われるようになっているので、それをそのまま適用したいと思います。

また、もともとの User では __str__ メソッドを定義し、インスタンスの出力時に username フィールドを出力するようにしていましたが、AbstractUser でも同様の __str__ メソッドが定義されているため、 CustomUser では __str__ メソッドをオーバーライドしないようにしています。

MEMO

正確に言うと、AbstractUser__str__ メソッドでは、USERNAME_FIELD に指定されているフィールドの値が出力されるようになっています

ただし、USERNAME_FIELD には 'username' が指定されているので、CustomUser でも User 同様の出力結果が得られることになります

さらに、age フィールドは、今までも必須フィールドとして扱っていたため、今回も必須フィールドとして定義するようにしています。そのため、createsuperuser コマンドでユーザーの作成ができるよう、REQUIRED_FIELDS には 'age' を追加しています。

スポンサーリンク

AUTH_USER_MODEL の設定

カスタムユーザー を定義した後には、プロジェクトで使用する「ユーザー管理モデル」の設定、すなわち AUTH_USER_MODEL の設定を忘れずに行うようにしましょう!

今回は、forum アプリに カスタムユーザー として CustomUser を定義していますので、プロジェクトの settings.py の最後に下記を追記すればよいことになります。

ユーザー管理モデルの設定
AUTH_USER_MODEL = 'forum.CustomUser'

これにより、プロジェクト内ではユーザー管理モデルとして CustomUser が利用されることになり、管理画面へのログインや createsuperuser コマンドでのユーザー作成時に CustomUser が利用されることになります。さらに、get_user_model 関数を実行すれば CustomUser が取得できるようにもなります。

カスタムユーザー の登録フォームの定義

続いて、ユーザー登録フォームの変更を行っていきます。

これまでは、下記のように、User のインスタンスを作成するためのフォームとして RegisterForm を定義していました。そして、この RegisterForm はモデルフォームクラスであり、ベースとなるモデルクラスとして User を指定するようにしていました。また、この RegisterForm では、username 入力用フィールド、email 入力用フィールド、age 入力用フィールドを持つようにしていました。 

RegisterFormの従来の定義
class RegisterForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ['username', 'email', 'age']

これからは CustomUser を「ユーザーを管理するモデルクラス」として使用することになるため、RegisterForm を CustomUser 作成用のフォームに変更していきたいと思います。さらに、今回完成するウェブアプリでは不要ではあるのですが、今後ログイン機能等を追加していくことを見越し、パスワードも入力可能なフォームに仕立てていきたいと思います。

そして、このようなフォームは、カスタムユーザー をベースにフォームを定義する で説明した内容にしたがって  UserCreationForm のサブクラスを定義することで実現できます。

具体的には、forms.py を下記のように変更してやれば、上記のような「CustomUser 作成用のフォーム」として RegisterForm を定義することができます(今回は PostForm の変更は不要です)。

forms.py
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm
from .models import Comment

User = get_user_model()

class RegisterForm(UserCreationForm):
    class Meta:
        model = User
        fields = [User.USERNAME_FIELD] + User.REQUIRED_FIELDS

class PostForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ['user', 'text']

        widgets = {
            'text': forms.Textarea
        }

ビューの変更

最後にビューを、User ではなく CustomUser を利用するように変更していきます。

基本的な使い方は他のモデルクラスと同じ で説明したように、カスタムユーザー の使い方は、基本的には他のモデルクラスと同じです。なので、今までの views.pyUser と記述している部分を CustomUser に置き換えてやるだけで、User ではなく CustomUser を利用するビューを実現することができます。

ただ、直接 CustomUser と記述すると、またクラス名を変更したときに、同様の置き換えが必要になって面倒です。なので、get_user_model 関数を実行してクラスオブジェクトを取得するようにし、この「get_user_model の返却値を受け取る変数」の 変数名User 部分を置き換えてやった方が後々の変更が楽になります。さらに、この「get_user_model の返却値を受け取る変数」の 変数名User にしてしまえば、そもそも User 部分の置き換えが不要となります。

ということで、views.py の変更は、views.py の先頭部分に get_user_modelimportUser = get_user_model() の追記、および、models.py からの Userimport を削除するだけで済むことになります。これで、User ではなく CustomUser を利用するビューが実現できます。

具体的には、もともとの views.py の先頭部分は下記のようになっていましたが、

変更前のviews.pyの先頭部分
from django.shortcuts import redirect, render, get_object_or_404
from .forms import RegisterForm, PostForm
from .models import User, Comment

これを下記のように変更してやるだけで、User ではなく CustomUser を利用するビューが実現できます。

変更後のviews.pyの先頭部分
from django.shortcuts import redirect, render, get_object_or_404
from .forms import RegisterForm, PostForm
from .models import Comment
from django.contrib.auth import get_user_model

User = get_user_model()

変更前の views.py では User.objects.all()User の全インスタンスを取得したり、get_object_or_404(User, id=user_id)iduser_id と一致する User のインスタンスを取得したり、さらには User のインスタンスに save メソッドを実行させてテーブルにレコードとしてインスタンスの保存を行ったりしていました。これらのテーブルやレコードの操作を UserCustomUser に置き換えても問題なく行うことが可能であることより、カスタムユーザー の使い方は、基本的には他のモデルクラスと同じであることを実感していただけるのではないかと思います。

また、カスタムユーザー の使い方が他のモデルクラスと同様であるため、テンプレートファイルに関しては今回修正は不要になります。ただし、修正が不要なのは、元々の User が持っているフィールドを全て CustomUser が持っているという点にも起因しています。User が持っているフィールドを CustomUser に持たせていないような場合は、テンプレートファイル等の変更も必要になるので注意してください。

スポンサーリンク

動作確認

以上で、今回の変更は完了となりますので、最後に今回実装した内容に関して動作確認を行なっていきましょう!

DB 関連の初期化

今回は、前回から models.py を大幅に変更しているため、そのままマイグレーションを実行するとエラーになる可能性が高いです。そのため、マイグレーションを実行する前に、データベース関連のファイルの削除を行いたいと思います。

ここから紹介する手順でデータベースの初期化を行うとデータベースやマイグレーション用の設定ファイルを完全に初期化することができます。ただ、今まで作成してきたレコードも無くなってしまいますので、この点は注意してください。ただ、一番確実&楽にマイグレーションのエラーを解決する手順ではあるので、練習でウェブアプリを開発していてマイグレーションのエラーがどうしても解決できない場合は、この手順で初期化するのが良いと思います。

まず、ターミナルやコマンドプロンプト等のコマンド実行可能アプリを開きます。そして、プロジェクトフォルダ(testproject フォルダ)の直下に移動してください。このフォルダには manage.py が存在するはずで、いつもマイグレーション等のコマンドを実行しているフォルダになります。

さらに、移動後に下記コマンドを実行してデータベースファイルを削除します。

% rm db.sqlite3

続いて、下記コマンドを実行してマイグレーション設定ファイルを削除します。

% rm forum/migrations/00*

以上で、データベース関連のファイルが全て削除されたことになります。

マイグレーションの実行

続いて、マイグレーションを実行していきたいと思います。

いつも通り、testproject フォルダの中、つまり manage.py が存在するフォルダで下記コマンドを実行してください。

% python manage.py makemigrations
% python manage.py migrate

これにより、CustomUser や Comment のテーブルがデータベースに追加されることになります。

開発用ウェブサーバーの起動

マイグレーションが完了した後は、いつも通り Django 開発用ウェブサーバーの起動を行います。マイグレーションを実行した時と同じフォルダで下記コマンドを実行すれば、Django 開発用ウェブサーバーが起動します。

% python manage.py runserver

ユーザー登録フォームでのユーザー作成の確認

ここからウェブアプリの動作確認に移っていきます。

最初に、ユーザー登録フォームでユーザーの登録、すなわち カスタムユーザー のインスタンスの追加が可能であることを確認したいと思います。

まずは、ウェブブラウザで下記の URL にアクセスしてみてください。

http://localhost:8000/forum/register/

これにより、ユーザー登録フォームが表示されると思います。注目ポイントは、RegisterFormfields に指定したフィールドに加え、パスワード 及び パスワード(確認用) フィールドが表示されている点になります。これは RegisterForm のスーパークラスの UserCreationForm によって追加されたフィールドになります。また、ユーザー名パスワード のフィールドにヘルプテキストが表示されるようになっていますが、これは AbstractUserAbstractBaseUser で、このようなヘルプテキストが表示されるようにフィールドの設定が行われているからになります。

ユーザー登録フォームの表示結果

続いて、これらの各種フィールドに適切なデータを入力した後に 送信 ボタンをクリックしてユーザー登録を実行してみてください。すると、ユーザー一覧画面に遷移し、登録したユーザーが表示されることが確認できると思います。このユーザーは CustomUser のインスタンスで、ユーザーを扱うクラスを User から CustomUser に変更しましたが、今まで通りの動作が実現できていますね!

追加したCustomUserのインスタンスの情報が表示される様子

また、コメント投稿フォームでも、今まで通り投稿者のユーザーを選択してコメントが投稿可能であることが確認できると思います。

今回のアプリではパスワードを明示的に扱わないため、パスワードの入力を行ったのに意味がなかったようにも思えますが、テーブルに保存されたレコードにはしっかりパスワードが保存されています(暗号化された状態で)。そして、このパスワードは、次回の連載で導入するログイン機能で利用されることになります。

createsuperuser コマンドでのユーザー作成の確認

次は、コマンド実行でのユーザー作成を行っていきます。runserver コマンドを一旦強制終了し(control + c で終了可能です)、次は下記のコマンドを実行してください。

python manage.py createsuperuser

コマンドを実行すると、CustomUserUSERNAME_FIELDREQUIRED_FIELDS に指定されているフィールド(usernameemailage)およびパスワードフィールド(確認用も含めて)の値の入力が促されるはずです。これらの入力を適切に行い、下記が出力されることを確認してください(入力時は、ユーザー名は他のユーザーとの重複は NG、パスワードは簡単すぎるものは NG であることに注意してください)。

Superuser created successfully.

上記の出力が確認できれば、再度下記コマンドで開発用サーバーを起動してください。。

% python manage.py runserver

そして、ウェブブラウザに下記 URL を指定し、再度ユーザー一覧のページを開いてみてください。

http://localhost:8000/forum/users/

すると、ユーザー一覧に createsuperuser コマンドで作成したユーザが表示されていることが確認できると思います。

createsuperuserコマンドで追加したCustomUserのインスタンスの情報が表示される様子

このユーザー一覧は CustomUser の全インスタンスを表示するページですので、この表示結果より、createsuperuser コマンドでも CustomUser の作成が可能であることが確認できたことになります。前述のとおり、この createsuperuser コマンドで作成されるのはスーパーユーザーで特別な権限を持ったユーザーとなります。例えば、このスーパーユーザーはウェブアプリの管理画面にログイン可能です。

管理画面へのログインの確認

ということで、最後に先ほど createsuperuser コマンドで作成したユーザーで管理画面にログイン可能であることを確認してみましょう!

まずは開発用ウェブサーバーを起動した状態で、ウェブブラウザから下記の URL にアクセスしてみてください。

http://localhost:8000/admin/

すると、下の図のようなログインフォームが表示されるはずです。

管理サイトのログインフォーム

これらのログインフォームに、先ほど createsuperuser コマンドに指定したユーザー名とパスワードを入力し、続けて ログイン ボタンを押してください。

すると、下の図のような管理画面にログインできるはずです。

管理サイトへのログイン後の画面

このログイン時には、ログインフォームに入力されたパスワードと、データベースに保存されている “ログインフォームに入力されたユーザー名のレコード” のパスワードとの照合が行われています(暗号化された状態のデータで照合される)。そして、照合 OK であった場合に、ログインに成功することになります。

createsuperuser コマンドに指定したパスワードでログインできたということは、createsuperuser コマンド実行時に入力したパスワードがしっかりデータベースに保存されていることを、つまり、CustomUser でのパスワード管理がバッチリ実現できていることを意味します。

MEMO

ユーザー登録フォームで登録したユーザーは「一般ユーザー」となるため、ログインフォームに入力したユーザー名とパスワードがデータベースに保存されているものと一致しても管理画面にはログインできません

こんな感じで、カスタムユーザー ではパスワード管理を行うことができ、これによりログイン機能等も実現可能です。今回は、管理画面という既に Djnago フレームワークに備えられたアプリでのログインを利用しましたが、次回の連載では、このログイン機能を、自分たちが開発するウェブアプリに搭載する手順について解説していきます。

まずは、今回説明した カスタムユーザー についてしっかり理解しておいてください。

また、管理画面の詳細についても、後ほどの Django 入門 の連載の中で解説をしていきます。

まとめ

このページでは、Django における カスタムユーザー について解説しました!

カスタムユーザー は単なるモデルクラスではなく、ユーザーを管理するために必要となる基本的な機能・フィールドを備えたモデルクラスとなります。この カスタムユーザー は、AbstractUser というクラスを継承することで簡単に定義することが可能です。また、カスタマイズを行うことで、開発するウェブアプリに適合した カスタムユーザー に仕立てていくこともできます。

上記のように、特別なモデルクラスではあるのですが、カスタムユーザー はあくまでもモデルクラスの一種となりますので、カスタムユーザー の基本的な使い方はモデルクラスと同様になります。

また、カスタムユーザーAUTH_USER_MODEL として設定することで、プロジェクト内でのログインやユーザー作成が カスタムユーザー に基づいて実行されるようになります。カスタムユーザー を定義した後は、AUTH_USER_MODEL の設定を忘れずに行うようにしましょう。

この カスタムユーザー を利用するメリットが発揮されるのは、特にログイン等のパスワードを扱う機能を実現する時になります。次回の連載となる下記ページでは、そのログイン機能について解説していきますので、是非下記ページも読んでいただければと思います!

ログインの実現方法の解説ページアイキャッチ 【Django入門10】ログイン機能の実現

同じカテゴリのページ一覧を表示