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

このページでは、Django での「カスタムユーザー」の作り方について解説していきます。

カスタムユーザーとは

カスタムユーザーとは、要はアプリ開発者が独自で作成する「ユーザー管理モデル(ユーザーを管理するモデル)」のことになります。

下記のページで Django でのログインの実現の仕方について解説していますが、ログインを実現するためにはユーザー管理モデルが必要になります。

Djangoでのログイン機能の実現方法解説ページアイキャッチ【Django】ログイン機能の実現方法(関数ベースビュー編) Djangoでクラスベースビューでログインを実現する方法の解説ページアイキャッチ【Django】ログイン機能の実現方法(クラスベースビュー編)

上記のページでは、このユーザー管理モデルとして、Django に標準で用意されている User を利用しました。

Django に標準で用意されているため、この User を利用することで簡単にユーザーを管理することができるようになるのですが、この User の利用は、実は Django の公式で非推奨とされています。

そのため、Django でウェブアプリを開発していく際には、ユーザー管理モデルとして User の代わりとなるカスタムユーザー(独自のユーザー)を作成し、そのモデルを利用してユーザーを管理していく必要があります。

このページでは、このカスタムユーザーモデルの作り方について解説していきます。

MEMO

もちろんお試しでログイン機能を実現したい場合などは User を利用しても良いです

ただ、実際に他のユーザーに利用してもらうようなアプリを開発するような場合は、User ではなくカスタムユーザーを利用した方が良いです

カスタムユーザーを利用する主な理由(User の利用が非推奨である理由)は下記となります

  • ユーザー管理モデルはアプリに応じて変更したくなることが多いが User は変更できない
  • 後から User の代わりにカスタムユーザーを利用しようと思ってもマイグレーション時にエラーが出て大変

カスタムユーザー作成時に必要になる手順

最初に、カスタムユーザーを作成し、さらにウェブアプリでカスタムユーザーを利用していくために必要になる手順の全体像を示しておきます。

まずは、カスタムユーザーをモデルとして定義して作成する必要があります。これは、クラス(モデル)の継承を利用することで簡単に実現することができます。

このページでは、AbstractUser を継承することでカスタムユーザーを作成していきます。

CustomUserをAbstractUserを継承して定義する様子

ただし、単に AbstractUser を継承しただけだと User と同等のモデルしか作成することができません。アプリに応じてユーザーで管理する情報やユーザーの動作を変更したい場合、フィールドやメソッドの追加等のカスタマイズを行う必要があります。

AbstractUserから継承したCustomUserをアプリに応じてカスタマイズする様子

さらに、このカスタムユーザーを用いてログイン等に必要な「認証」を実現していく必要があります。これは単に、アプリで認証時に使用するモデルとして作成したカスタムユーザーを設定してやれば良いのみになります。

アプリでの認証に使用するモデルをCustomUserに設定する様子

また、Django では管理画面(admin 画面)からユーザーの管理を行うことができます。管理対象が User からカスタムユーザーに変わるため、管理画面でカスタムユーザーを管理できるように設定する必要があります。

管理画面で管理するユーザーのモデルをCustomUserに設定する様子

あとは、フォームやビュー作成時に、必要に応じてカスタムユーザーを利用するようにしてやれば良いだけです。

ということで、カスタムユーザーを作成し、そしてそれをアプリで使用していくためには、大きく分けて下記の4つの手順が必要になることになります。ここからは、下記の4つの手順それぞれについて解説を行なっていきます。

フォームやビュー作成時のカスタムユーザーの利用については手順としての解説は省略しますが、最後の カスタムユーザーを利用するアプリの開発例 で具体的な実装例を紹介したいと思います。

スポンサーリンク

カスタムユーザーを定義する

では、まずはカスタムユーザーを定義する手順について解説していきます。

カスタムユーザーの定義の仕方

まず前提として、Django ではユーザー管理モデルを利用して認証等が実現されます。つまり、自身でユーザー管理モデルを作成する場合には、そのモデルで認証等が実現できる様に作成していく必要があります。こういった背景があるので、ユーザー管理モデルをゼロから自力で作成するのは非常に大変です。

そのため、カスタムユーザーは Django に標準で用意されているモデル(クラス)を継承し、それをカスタマイズしていくことで作成していくのが一般的な方法となります。

具体的には、カスタムユーザーは下記のようなモデル(クラス)を継承することで作成することができます。

  • AbstractUser を継承してカスタムユーザーを作る
  • AbstractBaseUser と PermissionsMixin を継承してカスタムユーザーを作る

AbstractUser を継承してカスタムユーザーモデルを定義する

User および、上記で挙げた3つのモデルには下の図のような継承関係があります。吹き出し内で簡単に各モデルで実現していること、さらに吹き出しの括弧内には各モデルで定義されるフィールドの例を示しています。

ユーザー関連の各クラスの継承関係を示す図

上の図にも記載の通り、AbstractUser にはユーザーを管理するための一般的なフィールドやメソッドが用意されていますので、下の図のように、AbstractUser を継承したモデルを定義するだけでユーザーを管理可能なモデルを作成することができます(AbstractUserAbstractBaseUserPermissionsMixin を継承しているので、AbstractUser を継承したモデルは権限管理や認証を行うことも可能です)。

各クラスとCustomUserとの継承関係を示す図

また、上の図で示すように、実は UserAbstractUser を継承して作成されています。User の具体的な定義は下記のようになります(Django 4.0.5 時点の定義になります)。

Userの定義
class User(AbstractUser):
    """
    Users within the Django authentication system are represented by this
    model.

    Username and password are required. Other fields are optional.
    """

    class Meta(AbstractUser.Meta):
        swappable = "AUTH_USER_MODEL"

ちょっと swappable の意味合いを私も理解していないのですが、上記を見ていただければ分かる様に、ほぼ UserAbstractUser を継承するのみで作成されていることが確認できると思います。

これはつまり、AbstractUser を継承さえすれば User 同等のカスタムユーザーを作成可能であることを意味します。

そのため、User 同等のカスタムユーザー(User と同じ機能を持つモデル)に関しては、AbstractUser を継承するのみで作成することが可能です。

また、User の持たないフィールドやメソッドをカスタムユーザーに持たせたいような場合も、ひとまず AbstractUser を継承してカスタムユーザーを定義し、その後にカスタムユーザーに必要なフィールドやメソッド(User に存在しないフィールドやメソッド)を追加していくのが一般的なカスタムユーザーの作成方法となります。

ということで、AbstractUser を継承してカスタムユーザーを作成する場合、まずは models.py を下記のように記述してカスタムユーザーを定義してやれば良いです(以降、作成するカスタムユーザーのモデル名は CustomUser として解説していきますが、 必要に応じて変更しても問題ないです)。

カスタムユーザーの定義
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    pass

もちろんアプリで使用するユーザー管理モデルが User と同等で良いのであれば、上記の定義のみでカスタムユーザーの作成は完了となります。

User 同等のモデルをわざわざ作成する必要もない様に感じるかもしれないですが、User は Django 本体で定義されているモデルなので変更することができません。

いや、正確には変更することはできるのですが、変更すると全アプリに影響を及ぼすことになるため、User 自体を変更することはやめた方が良いです。

それに対し、CustomUser はウェブアプリ(もしくはプロジェクト)毎に定義するモデルであるため、変更したとしても影響を及ぼすのはウェブアプリ内のみになります。

そのため、開発したいウェブアプリに応じて自由自在に変更することが可能です。

また、冒頭でも述べたように、User 自体を使うことは非推奨とされているため、User を利用したい場合であっても、上記のように CustomUsermodels.py に別途定義してやった方が良いです。

スポンサーリンク

AbstractBaseUser を継承して定義することも可能

ここまで AbstractUser を継承することを前提に解説してきましたが、AbstractUser ではなく AbstractBaseUser および PermissionsMixin を継承してカスタムユーザーを定義することも可能です。

CustomUserをAbstractBaseUserとPermissionsMixinを継承して定義する様子

AbstractUser を継承すると、当然ながら usernameemail などのユーザーを管理するためのフィールドもカスタムユーザーモデルに継承されることになります(具体的に継承されるフィールドは後述で紹介します)。

しかし、作成したいカスタムユーザーによっては継承されるフィールドが不要となることもあります。例えば、ユーザーの情報として username が不要なアプリも存在すると思います。

そんな時は、AbstractUser ではなく AbstractBaseUser と PermissionsMixin を継承する方が良いと思います。この場合、認証やグループ・権限管理などの、ユーザー管理を実現する上で最低限必要なフィールドしか継承されません。

最低限必要なフィールドしか継承されないため、不要なフィールドが継承されることなく、後から自分で好きなもののみをフィールドとして持たせることが出来ます(もちろんメソッドも)。

ただ、自由度が高い分、AbstractUser を継承するときに比べて実装難易度も上がります。

この AbstractBaseUser と PermissionsMixin を継承してカスタムユーザーを作成していく手順については、別途下記ページで解説していますので、必要に応じてこちらのページも参考にしていただければと思います。

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

カスタムユーザーをカスタマイズする

さて、先ほども説明したように、User 同等のカスタムユーザーは AbstractUser を継承して定義するだけで作成することが出来ます。

ただし、アプリによっては AbstractUser から継承するフィールドやメソッドのみでは機能的に足りない場合もあるため、ここでフィールドやメソッドの追加等を行う手順について解説していきたいと思います。

AbstractUser から継承されるフィールド・メソッド

ただ、CustomUser に対して不足しているフィールドやメソッドの追加を行おうと思っても、CustomUser の持つフィールドやメソッドが分からないと、何が不足しているか分からないですよね…。

なので、まずは CustomUser の持つフィールドやメソッド、すなわち AbstractUser から継承されるフィールドやメソッドについて紹介しておきたいと思います。

AbstractUser で定義されているフィールドとメソッドには下記の様なものが存在します。CustomUserAbstractUser を継承して作成しているため、CustomUser もこれらのフィールドとメソッドを持つことになります。

  • フィールド
    • usernameCharField
    • first_nameCharField
    • last_nameCharField
    • emailEmailField
    • is_staff BooleanField
    • is_activeBooleanField
    • date_joinedDateTimeField
  • メソッド
    • clean
    • get_full_name
    • get_short_name
    • email_user

上記は、あくまでも AbstractUser で定義されたフィールドとメソッドです。

前述の通り、AbstractUser 自体も AbstractBaseUserPermissionsMixin を継承して作成されているモデルなので、CustomUserAbstractBaseUserPermissionsMixin で定義されているフィールドやメソッドも継承することになります。例えば passwordlast_login などの認証用のフィールドや groupis_superuser などのグループ・権限管理用のフィールドも継承されます。

ただ、これらのフィールドやメソッドに関しては、認証機能やグループ・権限管理機能をカスタマイズしたいような場合でなければ意識する必要はないため、基本的には上記で挙げたフィールドやメソッドだけを意識し、開発するアプリに不足しているものを追加していけば良いと思います。

また、上記で列挙したメソッドの具体的動作を知りたい方は、是非 AbstractUser の定義を自身で確認してみてください。

VSCode の場合、クラスの定義は下記ページで紹介している手順で簡単に確認することができます。

VSCodeでのクラス定義の確認方法の解説ページアイキャッチ【Django】VSCodeでクラスの定義を簡単に確認する方法

スポンサーリンク

フィールドの追加

CustomUser に既に存在するフィールドについては理解していただけたと思いますので、続いてはフィールドの追加の仕方を解説していきたいと思います。

カスタムユーザーに関しても、通常の Python におけるサブクラスと同様にしてカスタマイズすることができます。

具体的には、クラス変数の追加やメソッドの追加、メソッドのオーバーライドなどが可能です。

フィールドの追加方法

フィールドの追加に関しては、クラス変数の追加によって実現することができます。

例えば下記のように CustomUser にクラス変数 nicknameheightweight を追加すれば、それぞれ文字列型のフィールドとして nickname が、さらに浮動小数点数型のフィールドとして heightweight がカスタムユーザーに追加されることになります。

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

class CustomUser(AbstractUser):
    nickname = models.CharField(max_length=100)
    height = models.FloatField()
    weight = models.FloatField()

入力必須フィールドの設定

上記の通り、フィールドの追加自体は簡単に行うことができるのですが、入力必須のフィールドを追加する場合は注意が必要になります。

フィールドはデフォルトでは blank オプションが False で設定されており、入力必須のフィールドとして作成されることになります。

つまり、先ほど追加した nicknameheightweight の3つのフィールドは全て入力必須フィールドとなります。

そのため、先ほど作成した CustomUser のユーザーを追加する際には nicknameheightweight の3つのフィールドも設定できるようにする必要があるので注意してください。

例えばユーザーを追加する入力フォームにおいて、入力必須のフィールドの値の設定もできるように入力エントリー等を追加する必要があります。

入力必須フィールドの入力受付を行うようにフォームを作成する様子

このように、入力フォームから入力を受け付けてユーザーを追加する場合は、自身が作成するフォームで入力必須のフィールドの値を入力できるようにしてやれば良いだけです。

ですが、createsuperuser コマンドでユーザーを追加する場合は、別途カスタムユーザーの設定を行わない限り、usernameemailpassword しか入力受付が行われないので注意してください。

つまり、前述の CustomUser のように入力必須フィールドを追加した場合、デフォルトでは createsuperuser コマンド実行時のユーザー追加時に nicknameheightweight を入力・設定することができず、必ずユーザー追加に失敗することになります。

createsuperuser コマンドからもユーザーを追加できるようにするためには、createsuperuser コマンド実行時に入力受付されるフィールドとして nicknameheightweight を設定してやる必要があります。

この設定は、REQUIRED_FILEDS のクラス変数に入力必須フィールドをリスト形式で指定することで実現できます。

ただし、ここがちょっとややこしいのですが、この REQUIRED_FILEDS に指定するリストに USENAME_FIELDpassword のフィールドが含まれるとエラーになるので注意してください。この USERNAME_FIELDpassword のフィールドは REQUIRED_FILEDS に指定するリストに含めなくても自動的に createsuperuser 実行時に入力受付が行われるようになっています。

また、USERNAME_FIELD とは、ユーザーを一意に識別するためのフィールドであり、デフォルトでは username が設定されています。例えば、ユーザーを一意に識別するためのフィールドを username ではなく email(メールアドレス)にしたい場合は USERNAME_FILED の設定を別途行う必要があります。

ですが、今回は username でユーザーを一意に識別することを前提に解説していきたいと思いますので、USENAME_FIELD の設定は行いません。

上記の解説を踏まえると、CustomUser モデルのクラス変数で下記のように REQUIRED_FILEDS を設定することで、createsuperuser 実行時に usernameemailnicknameheightweightpassword の入力受付が行われるようになり、上手くユーザーを作成することができるようになります。

REQUIRED_FIELDSの設定
class CustomUser(AbstractUser):
    nickname = models.CharField(max_length=100)
    height = models.FloatField()
    weight = models.FloatField()

    # usernameとpasswordの指定は不要
    REQUIRED_FIELDS = ["email", "nickname", "height", "weight"]

ちなみに、REQUIRED_FILEDS のデフォルト設定は ["email"] となっています。こういった各種変数のデフォルト設定は AbstractUser の定義から確認することができます。

(参考)フィールドの上書き方法

また、フィールドは追加だけではなくて削除する様なことも可能ではあります。

例えば、date_joined というフィールドが不要であれば、下記の様に date_joinedNone で上書きしてやれば、CustomUser から date_joined フィールドを削除することも可能です。

date_joinedの削除
from django.db import models
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    date_joined = None

同様にクラス変数を上書きしてやることで、AbstractUser から継承されるフィールド・メソッド で挙げたフィールドのオプション等を変更することも可能です。例えば email は入力が必須ではないフィールドなのですが、次のように email を上書きしてやれば、email を入力必須のフィールドに変更することも可能です。

emailの上書き
from django.db import models
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    email = models.EmailField(blank=False)

ただ、こういったフィールドの上書きは他のサイト等で紹介されていないやり方になりますし、AbstractUser ではなく AbstractBaseUser を継承するようにすれば、そもそも不要なフィールドを持たないようにカスタムユーザーを作成することが可能であり、おそらくこちらのやり方の方が推奨されているのではないかと思います。

前述の通り、AbstractBaseUser を継承してカスタムユーザーを作成する手順については別途下記ページで解説していますので、不要なフィールドを持たないカスタムユーザーを作成したいような場合はこちらを参考にしていただければと思います。

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

メソッドの追加

また、メソッドの追加も可能で、これによりフィールドの情報を加工して取得する様なことが可能になります。

例えば下記の様にメソッドを CustomUser に追加すれば、CustomUser のインスタンスに get_bmi を実行させることで、そのインスタンスのユーザーの BMI 値を取得することができる様になります。

メソッドの追加
from django.db import models
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    height = models.FloatField()
    weight = models.FloatField()

    def get_bmi(self):
        """Return the bmi for the user."""
        return self.weight / ((self.height / 100) * (self.height / 100))

メソッドのオーバーライド

同様に、メソッドのオーバーライドも可能で、これにより AbstractUser で定義されたメソッドの動作を上書きすることが可能です。

このオーバーライドは、AbstractUser から継承されるフィールド・メソッド で挙げたメソッドと同じ名前のメソッドを CustomUser に追加することで実現できます。

例えば、AbstractUser で定義されている get_short_name は  first_name フィールドの文字列を単に返却するメソッドになりますが、下記の様にメソッドを CustomUser に追加すれば get_short_name がオーバーライドされ、CustomUser に新たに追加した nickname フィールドの文字列を返却するように動作を上書きすることができます。

メソッドのオーバーライド
from django.db import models
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    nickname = models.CharField(max_length=100)

    def get_short_name(self):
        """Return the short name for the user."""
        return self.nickname

こんな感じで、フィールドの追加やメソッドの追加・オーバーライドを行なっていくことで、アプリに応じたカスタムユーザーを作成していくことができます。

スポンサーリンク

認証にカスタムユーザーを利用する

続いて、認証に利用するユーザー管理モデルを先ほど作成した CustomUser に設定していきたいと思います。

Django で開発するアプリにおいては、デフォルト設定では認証時に User モデルを使用することが前提となっています。

ですので、せっかくカスタムユーザーを作成したとしても、デフォルト設定のままだと認証に User モデルが利用されることになって意味がありません。

そのため、カスタムユーザーを定義した際には、認証に使用するユーザー管理モデルとしてカスタムユーザーを設定してやる必要があります。

この、認証で使用するユーザー管理モデルの設定は settings.py で行うことができます。

より具体的には、下記のように settings.pyAUTH_USER_MODEL の定義を加えることで、アプリ内で利用するユーザー管理モデルを models.py で定義したカスタムユーザーに設定することができます。

認証時に使用するModelの設定
AUTH_USER_MODEL = 'アプリ名.カスタムユーザーのModel名'

例えば アプリ名python manage.py startapp で作成するアプリの名前) が login_app、さらに models.py で定義した カスタムユーザーのModel名CustomUser であれば、settings.py には下記を追記することになります。

認証時に使用するModelの設定例
AUTH_USER_MODEL = 'login_app.CustomUser'

上記の設定を行うことで、認証時に使用するユーザー管理モデルとして カスタムユーザーを定義する で定義した CustomUser が使用されるようになり、マイグレーション実行時にデータベースに login_app_customuser というテーブルが作成されることになります(Django ではモデル毎にテーブルが作成される)。

また、AUTH_USER_MODEL を変更せずにマイグレーションを実行した場合、カスタムユーザーを定義 で定義したモデルのテーブルだけでなく、AUTH_USER_MODEL にデフォルトで設定されている User のテーブルまで作成されることになります。

この際には、おそらく下記のようなエラーが発生することになるので注意してください。

% python manage.py makemigrations
auth.User.groups: (fields.E304) Reverse accessor for 'auth.User.groups' clashes with reverse accessor for 'login_app.CustomUser.groups'.
        HINT: Add or change a related_name argument to the definition for 'auth.User.groups' or 'login_app.CustomUser.groups'.

どうやら AbstractUser を継承して作成したカスタムユーザーモデルと User とは共存できないようになっており、両方のテーブルが作成されると上記のエラーが発生するようです。そのため、どちらか一方のモデルのテーブルは作成されないようにする必要があります。

このカスタムユーザーと User の両方のテーブルが作成されてしまう原因は、カスタムユーザーを定義したにも関わらず AUTH_USER_MODELUser が設定されている点にありますので、AUTH_USER_MODEL に定義したカスタムユーザーを設定することで正常にマイグレーションを行うことができるようになります。これは、認証に使用するユーザー管理モデルが User ではなくなるため、マイグレーション時に Userのテーブルが作成されなくなるからです。

逆に、ユーザー管理モデルを User に戻したい場合は、models.py にカスタムユーザーの定義が存在すると上記のエラーが発生することになるため、models.py からカスタムユーザーの定義を消す or コメントアウトする必要があります。

MEMO

おそらく別の手段でもエラーは回避できると思うのですが、おそらく上記のやり方がエラー回避方法として一番簡単だと思います

管理画面でカスタムユーザーを利用する

次は、管理画面関連の設定について解説していきます。

管理するユーザーをカスタムユーザーに設定する

ここまで紹介してきたような models.pysettings.py の変更によりカスタムユーザーが作成され、さらにウェブアプリ内で認証を行う際にカスタムユーザーが使用されるようになりました。

ウェブアプリを動作させるだけであれば、ここまでの変更内容のみで上手くいくのではないかと思います。

ただし、現状のままだと、下の図のように管理画面(admin 画面)でユーザーに関するセクションが表示されず、管理画面でのユーザー管理が出来ない状態になっています。そのため、続いて管理画面でカスタムユーザーモデルのユーザーの管理を行うための手順を解説していきます。

管理画面でユーザーの管理が行えない様子

といっても、管理画面でカスタムユーザーの管理を行うための手順は単純で、単にアプリフォルダ内にある admin.py を下記のように変更すれば良いだけになります。

カスタムユーザーを管理する
from django.contrib import admin
from django.contrib.auth import get_user_model

CustomUser = get_user_model()

admin.site.register(CustomUser)

get_user_model は、settings.pyAUTH_USER_MODEL に指定されているモデルを取得する関数になります。認証にカスタムユーザーを利用する で解説した通りに settings.py を変更した場合、この返却値として models.py で定義した CustomUser モデルが取得されることになります。

さらに、get_user_model 関数の返却値を引数に指定して admin.site.register を実行すれば、管理画面で管理するユーザーとして AUTH_USER_MODEL に指定されているモデル、すなわち models.py で定義した CustomUser が指定されることになります。

そして、これによって、下の図のように管理画面にユーザーを管理するセクションが表示されるようになり、カスタムユーザーを管理画面で管理することができるようになります。

admin.site.registerの実行により管理画面でユーザーの管理を行うことができるようになった様子

また、上記のスクリプトのように、認証に利用しているモデルを指定する際には、直接モデル名を指定するのではなく、get_user_model 関数を使用するように心がけると良いと思います。

直接モデル名を指定していると、AUTH_USER_MODEL を変更した際に、モデル名を指定している箇所全ての変更を行う必要があります。

ですが、get_user_model 関数で取得したモデルを指定するようにしておけば、AUTH_USER_MODEL を変更した際に get_user_model 関数の返却値も自動的に変更されることになり、モデルの指定箇所の変更が不要になって手間が減ります(上記の場合は admin.site.register の引数の変更が不要)。

ビューやフォーム等でユーザーのモデルを指定する場合も、直接モデルを指定するのではなく、get_user_model 関数の返却値を指定するようにしてやった方が、AUTH_USER_MODEL 変更時の手間が減り、変更しやすいソースコードに仕立てることができて良いと思います。

スポンサーリンク

管理画面をカスタマイズする

ただし、先ほど示した admin.py では、管理画面からカスタムユーザーを管理するための必要最低限の設定しか行われません。

実際の画面は後述の カスタムユーザーを利用するアプリの開発例 でアプリを実際に作りながら紹介しますが、先ほど示したスクリプトのままだとユーザー追加時にパスワードがそのまま表示されてしまいますし、ユーザー追加時に入力不要なフィールドまで入力受付が行われて冗長です。

こういった問題点は、管理画面(特にユーザー管理を行う画面)をカスタマイズすることで解決することが可能です。

この管理画面(ユーザー管理画面)のカスタマイズ方法については下記ページで解説していますので、必要に応じて是非このページを読み終わった後にでも読んでみていただければと思います。

Djangoでのユーザー管理画面のカスタマイズ方法の解説ページアイキャッチ【Django】ユーザー管理画面(admin)のカスタマイズ

カスタムユーザーを利用するアプリの開発例

以上が、カスタムユーザー作成およびアプリをカスタムユーザーを利用して動作させるために必要な手順となります。

最後に、ここまで解説してきた内容を踏まえながら、カスタムユーザーを利用する簡単なアプリを作成し、動作確認を行なっていきたいと思います。

プロジェクトとアプリの作成

まずは、いつも通りプロジェクトとアプリを作成していきます。

最初に、下記コマンドを実行してプロジェクト login_project を作成します。

% django-admin startproject login_project

続いて、上記コマンドで作成される login_project フォルダの中に移動し、さらに startapp を実行してアプリ login_app を作成します。

% cd login_project
% python manage.py startapp login_app

次に、login_project フォルダの中にある settings.py 内の INSTALLED_APPS を下記のように変更し、プロジェクトに対してアプリを登録します。

アプリの登録
# Application definition

INSTALLED_APPS = [
    'login_app', # 追加
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

スポンサーリンク

カスタムユーザーの作成

続いて、カスタムユーザーを定義するカスタムユーザーをカスタマイズする の内容を踏まえてカスタムユーザーを作成していきたいと思います。

今回は、User に対して nicknameheightweight の3つのフィールドを追加したカスタムユーザーを作成していきます。さらに、BMI を返却する get_bmi メソッドの追加と、get_short_name メソッドのオーバーライドを行なっていきたいと思います。

そのために、login_app フォルダの中にある models.py を開き、下記のように変更します。

カスタムユーザーの作成
from django.db import models
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    nickname = models.CharField(max_length=100)
    height = models.FloatField()
    weight = models.FloatField()

    def get_bmi(self):
        """Return the bmi for the user."""
        return self.weight / ((self.height / 100) * (self.height / 100))

    def get_short_name(self):
        """Return the short name for the user."""
        return self.nickname

カスタムユーザーを定義する や カスタムユーザーをカスタマイズする で解説したように、AbstractUser を継承したモデル CustomUserUser とほぼ同等のモデルとなります。さらに CustomUser に対してフィールドやメソッドを追加することで、User が持っていないフィールドやメソッドを CustomUser に持たせることができます。

また、get_short_name に関しては User も持っているメソッドになりますが、オーバーライドを行なっているため、CustomUserget_short_nameUserget_short_name から動作が変更されていることになります。

AUTH_USER_MODEL の設定

通常であれば、models.py でモデルを定義した後はマイグレーションを行うのですが、認証にカスタムユーザーを利用する で解説した通り、カスタムユーザーを定義しただけではマイグレーションを行うとエラーが発生します。

そのため、マイグレーションの前に settings.py を変更して AUTH_USER_MODEL の設定を行なっていきます。

具体的には、settings.py の最後に下記を追記し、アプリ内で認証時に利用するユーザー管理モデルとして先ほど作成した CustomUserを設定します。

AUTH_USER_MODELの設定
AUTH_USER_MODEL = 'login_app.CustomUser'

マイグレーションの実行

続いてマイグレーションを実行していきましょう!

startproject で作成された login_project フォルダ内で下記の2つのコマンドを実行してみてください。おそらくエラーが発生することなく正常にマイグレーションが実行できるはずです。

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

このマイグレーションによって login_app.customuser というテーブルが作成されることになります。

そして、この login_app.customuser テーブルには、CustomUser に追加した nicknameheightweight の3つの列が存在しているはずです(下の図は VSCode の SQLite Viewer プラグインで login_app.customuser テーブルを表示した結果となります)。

login_app.customuser テーブルの表示結果

あとは、ビュー等からレコードの保存や取得等を行うことで、カスタムユーザーの管理を実現できることになります。

スポンサーリンク

スーパーユーザーの追加

ビューの作成などを行う前に、次は管理画面でカスタムユーザーを管理できるように設定していきたいと思います。

この管理画面にアクセスするためにはスーパーユーザーが必要ですので、まずはスーパーユーザーを追加していきましょう!

このスーパーユーザーの追加を行うために、startproject で作成された login_project フォルダ内で下記コマンドを実行してみてください。

% python manage.py createsuperuser

おそらく、ここまで紹介してきた変更だけでは上記実行時に、次のようなエラーが発生するはずです。

% python manage.py createsuperuser
Username: YamadaHanako
Email address: hanako@yamada.jp
Password: 
Password (again): 
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/backends/utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/db/backends/sqlite3/base.py", line 477, in execute
    return Database.Cursor.execute(self, query, params)
sqlite3.IntegrityError: NOT NULL constraint failed: login_app_customuser.height
〜略〜
django.db.utils.IntegrityError: NOT NULL constraint failed: login_app_customuser.height

このエラーが発生しているのは、createsuperuser を実行して CustomUser のユーザーを追加する際に、入力必須となっているフィールド(nicknameheightweight)が入力されていないためです。

そもそも createsuperuser 実行時にこれらのフィールドの入力受付が行われていないので入力することは不可能です…。

ですので、createsuperuser 実行時にこれらのフィールドの入力受付が行われるよう修正する必要があります。そして、この修正は、入力必須フィールドの設定 で解説したように REQUIRED_FIELDS の設定を追加することにより実現できます。

ということで、下記のように models.pyCustomUser を変更してみましょう。

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

class CustomUser(AbstractUser):
    nickname = models.CharField(max_length=100)
    height = models.FloatField()
    weight = models.FloatField()

    # ↓追加
    REQUIRED_FIELDS = ["email", "nickname", "height", "weight"]

    def get_bmi(self):
        """Return the bmi for the user."""
        return self.weight / ((self.height / 100) * (self.height / 100))

    def get_short_name(self):
        """Return the short name for the user."""
        return self.nickname

さらに、先ほど同様に下記コマンドを実行してスーパーユーザーを追加してみてください。REQUIRED_FIELDS の設定を追記したことで、今度は CustomUser における入力必須フィールドである nicknameheightweight の入力が行うことができ、スーパーユーザーの追加にも成功するはずです。

% python manage.py createsuperuser
Username: YamadaHanako
Email address: hanako@yamada.jp
Nickname: Hana  
Height: 170
Weight: 50
Password: 
Password (again): 
Superuser created successfully.

このように、カスタムユーザーを作成してフィールドを追加した場合、ユーザー追加時の処理等も追加したフィールドを考慮して動作するように設定する必要があるので注意してください(特に入力必須フィールドの場合は注意が必要です)。

管理画面の設定

次は、管理画面でカスタムユーザーを管理できるように設定を行なっていきます。

まずは現状を把握するために管理画面にアクセスしてみましょう!

管理画面にアクセスする際には、Django の開発用ウェブサーバーを起動しておく必要がありますので、最初に下記コマンドを実行しておいてください。

% python manage.py runserver

コマンド実行後、次は下記 URL をウェブブラウザで開くと、管理画面へのログイン画面が表示されるはずです。

http://localhost:8000/admin/

このログイン画面では、先ほど作成したスーパーユーザーのユーザー名とパスワードを指定して Log in ボタンを押してください。

ログインに成功した際には、下の図のような管理画面が表示されるはずです。

管理画面でユーザーの管理が行えない様子

上の図を見ていただければわかる通り、現状では管理画面で行えるのはグループの管理のみであり、ユーザーの管理が行えない状態になっています。

次は、管理画面からユーザーの管理が行えるように管理画面のカスタマイズを行なっていきます。

管理画面でカスタムユーザーを利用する で説明したように、admin.pyadmin.site.register を実行してカスタムユーザーを登録してやることにより、管理画面からユーザーの管理を行うことができるようになります。

ということで、login_app フォルダの下にある admin.py を下記のように変更しましょう!

カスタムユーザーの登録
from django.contrib import admin
from django.contrib.auth import get_user_model

CustomUser = get_user_model()

admin.site.register(CustomUser)

変更後に、再度下記 URL をウェブブラウザで開いてみてください(必要に Django 開発用ウェブサーバーを起動してください)。

http://localhost:8000/admin/

今度は LOGIN_APP というセクションが現れ、Users というリンクが表示されるようになっているはずです。

admin.site.registerの実行により管理画面でユーザーの管理を行うことができるようになった様子

そのリンクをクリックすれば、下の図のように「ユーザー一覧リスト」が表示されます。

管理画面でユーザー一覧リストが表示される様子

ユーザー一覧リストからユーザー名をクリックすれば、下の図のように「ユーザー詳細フォーム」が表示され、さらにここでユーザーの情報の変更も可能です。

管理画面でユーザーの詳細が表示される様子

また、ユーザー一覧リストの右上にある ADD USER + のボタンをクリックすれば、下の図のような「ユーザ作成フォーム」が表示され、必要な入力を行なって画面下の SAVE ボタンをクリックすることでユーザーの追加を行うことができます(太字部分が入力必須項目となります)。

管理画面でユーザー作成フォームが表示される様子

ユーザー詳細フォームやユーザー作成フォームでは、CustomUser で追加した nicknameheightweight の入力や変更も可能であり、管理画面から CustomUser のユーザーの管理を行えていることを確認できると思います。

カスタムユーザーに追加したフィールドが入力可能であることを示す図

こんな感じで、admin.py の変更により、独自で作成したユーザーの管理を行うことができるようになります。

ただ、上記の「ユーザー一覧リスト」にはユーザー名しか表示されていませんので一覧性が悪いですし、「ユーザー詳細フォーム」や「ユーザー作成フォーム」では CustomUser の持つフィールド全てが表示されているので、ちょっと冗長な気もします。

さらに、ユーザー追加時等に入力したパスワードがそのまま表示されてセキュリティ的にもイマイチです。

パスワードがそのまま表示されてしまう様子

こういった具合に、ユーザー管理を行う画面・フォーム等に不満がある場合は管理画面のカスタマイズを行なった方が良いです。

前述でも紹介しましたが、この管理画面(ユーザー管理画面)のカスタマイズ方法については下記ページで解説していますので、必要に応じて参考にしていただければと思います。

Djangoでのユーザー管理画面のカスタマイズ方法の解説ページアイキャッチ【Django】ユーザー管理画面(admin)のカスタマイズ

フォーム・ビュー・テンプレートの作成

ここまでの変更によって、カスタムユーザーが定義され、カスタムユーザーを管理画面から管理・作成することができるようになりました。

最後に、カスタムユーザーをフォームやビュー等から利用する例を紹介していきます。

実現するページは3つのみで、1つ目はユーザーアカウント(カスタムユーザー)を追加するページ、2つ目はログインを行うページ、3つ目はログインユーザーのニックネームと BMI を表示するページになります。

ユーザーアカウントの作成やログインに関しては下記ページで詳しく解説していますので、これらを実現するための手段の詳細を知りたい方は下記ページを参照して頂ければと思います。

Djangoでのログイン機能の実現方法解説ページアイキャッチ【Django】ログイン機能の実現方法(関数ベースビュー編)

このページでは、スクリプトの紹介および、ユーザーに関連する説明のみを行なっていきたいと思います。

フォームの作成

まずは login_app フォルダの下に forms.py を新規作成し、中身を下記のように変更します。

forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import get_user_model

CustomUser = get_user_model()

class SignupForm(UserCreationForm):
    class Meta:
        model = CustomUser
        fields = [CustomUser.USERNAME_FIELD] + CustomUser.REQUIRED_FIELDS + ['password1', 'password2']

class LoginForm(AuthenticationForm):
    pass

UserCreationFormAuthenticationForm に関しては先ほど紹介した  【Django】ログイン機能の実現方法(関数ベースビュー編) で解説していますので、詳細を知りたい方は【Django】ログイン機能の実現方法(関数ベースビュー編) をご参照ください。

上記でポイントになるのは、まず modelmodels.py に定義した CustomUser を指定する点になります。この CustomUser は、settings.pyAUTH_USER_MODELmodels.py で定義した CustomUser を指定している場合、上記のように get_user_model から取得することが可能です。

また、SignupFormfields には、CustomUser 作成時に必須となる情報が入力できるように、フォームで入力受付を行うフィールドをリスト形式で指定する必要があります。

USERNAME_FIELDusername)とパスワード(password1password2)以外で入力受付を行いたいフィールドは CustomUserREQUIRED_FIELDS で指定していますので、fields にはこれらを連結したリストを指定すれば良いため、上記のように SignupFormfields を指定するようにしています。

MEMO

UserCreationForm を継承したフォームの場合、fields への指定に password1password2 を省略した場合でも、表示される入力フォームには password1password2 に対するエントリーが表示されます

テンプレートの作成

続いてテンプレートを作成していきます。

といっても、今回用意するテンプレートは基本的に下記ページの ログイン機能実現用のスクリプト で紹介している signup.htmllogin.htmluser.html とほぼ同等のものなので、詳細な説明は省略させていただきます(user.html はニックネームと BMI を表示するように変更しています)。

Djangoでのログイン機能の実現方法解説ページアイキャッチ【Django】ログイン機能の実現方法(関数ベースビュー編)

これらのファイルの作成フォルダが login_app/templates/login_app/ であることに注意してください。

signup.html
{% load static %}
<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>ユーザー登録</title>
</head>
<body>
    <h1>ユーザー登録</h1>
    <form action="{% url 'signup' %}" method="post">
    {% csrf_token %}
        {{ form.as_p }}
        <p><input type="submit" value="登録"></p>
    </form>
</body>
</html>
login.html
{% load static %}
<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>ログイン</title>
</head>
<body>
    <h1>ログイン</h1>
    <p>{{message}}</p>
    <form action="{% url 'login'%}" method="post">
    {% csrf_token %}
        {{ form.as_p }}
        <p><input type="hidden" name="next" value="{{next}}"></p>
        <p><input type="submit" value="ログイン"></p>
    </form>
    <p><a href="{% url 'signup'%}">ユーザー登録</a></p>
</body>
</html>
user.html
{% load static %}
<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>{{title}}</title>
</head>
<body>
    <h1>{{nickname}}</h1>
    <p>BMI:{{bmi}}</p>
</body>

</html>

ビューの作成

次はビューを作成していきます。

こちらも基本的に下記ページの ログイン機能実現用のスクリプト で紹介している views.py と似ている部分が多いのですが、簡略化して logout_viewother_view を削除したり、リダイレクト関連の処理を省略している部分もあるので注意してください。

Djangoでのログイン機能の実現方法解説ページアイキャッチ【Django】ログイン機能の実現方法(関数ベースビュー編)

また、user_view では models.pyCustomUser でオーバーライドや定義を行なった get_short_nameget_bmi メソッドを使用し、このメソッドから取得した文字列や値をテンプレートに渡すようにしています。

views.py
from django.shortcuts import render, redirect
from .forms import SignupForm, LoginForm
from django.contrib.auth import login
from django.contrib.auth.decorators import login_required

def signup_view(request):
    if request.method == 'POST':

        form = SignupForm(request.POST)
        if form.is_valid():
            user = form.save()
            login(request, user)
            return redirect(to='/login_app/user/')

    else:
        form = SignupForm()
    
    param = {
        'form': form
    }

    return render(request, 'login_app/signup.html', param)

def login_view(request):
    if request.method == 'POST':
        next = request.POST.get('next')
        form = LoginForm(request, data=request.POST)

        if form.is_valid():
            user = form.get_user()

            if user:
                login(request, user)
                return redirect(to='/login_app/user/')

    else:
        form = LoginForm()

    param = {
        'form': form,
    }

    return render(request, 'login_app/login.html', param)

@login_required
def user_view(request):
    user = request.user

    params = {
        'nickname': user.get_short_name(),
        'bmi': user.get_bmi()
    }

    return render(request, 'login_app/user.html', params)

1つ説明を加えておくと、user_view 関数の引数 request のデータ属性 usersettings.pyAUTH_USER_MODEL に指定したモデルのインスタンスとなります。

AUTH_USER_MODEL には models.py で定義した CustomUser を指定しているため、request.userCustomUser のインスタンス(より具体的にはページにアクセスしてきたユーザーのインスタンス)となりますので、request.userCustomUser で定義したメソッドを実行させることができます。

実際に、上記の user_view 関数では get_short_nameuser.get_bmi メソッドを実行させています。もちろんメソッドだけでなく、CustomUser に用意されているクラス変数やデータ属性(インスタンス変数)も利用可能です。

スポンサーリンク

パスとビューの関連付け

最後にパスとビューの関連付けを行なっていきます。

まず login_project フォルダの下の urls.py を下記のように変更し、login_app/ から始まるパスが指定された際に login_app フォルダ下の urls.py を参照するようにします。

login_project/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login_app/', include('login_app.urls'))
]

続いて、その参照先となる urls.py を login_app フォルダの下に下記のように作成します。

これにより、path の第1引数で指定したパス(URL)へのアクセスがあった際に、第2引数で指定した views.py の各関数が実行されるようになります。

login_app/urls.py
from . import views
from django.urls import path

urlpatterns = [
    path('signup/', views.signup_view, name='signup'),
    path('login/', views.login_view, name='login'),
    path('user/', views.user_view, name='user'),
]

動作確認

ここまでフォームやビューの作成を行なってきましたので動作確認をしてみましょう!

まずは Django 開発用ウェブサーバーを起動し(python manage.py runserver を実行)、さらに下記 URL をウェブブラウザで開いてみてください。

http://localhost:8000/login_app/signup/

そうすると、下の図のようなユーザー登録フォームが表示されるはずです。

カスタムユーザーの作成画面

forms.py で SignupFormfields に指定したフィールドへの入力を行うことができるようになっている点を確認できると思います。

さらに、上の図の登録フォームにユーザー名やニックネーム等の全ての入力を行なった後に 登録 ボタンを押せば、次は下の図のようなユーザーの情報表示ページに遷移するはずです。

カスタムユーザーに追加したフィールドの情報が表示される様子

このページでは、ユーザーのニックネームと BMI が表示されるようになっています。これらの文字列や値は、ビューで CustomUser のメソッドを実行することで取得され、それらをテンプレートに組み込むことでページとして表示された結果となります。

最後に下記 URL をウェブブラウザで表示してみてください。

http://localhost:8000/login_app/login/

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

表示されるログインフォーム

このログインフォームに、今度は スーパーユーザーの追加 で追加したユーザーのユーザー名とパスワードを入力して ログイン ボタンを押してみてください。ログインに成功し、先ほど同様にユーザー情報表示ページに遷移するはずです。

ただし、表示されるニックネームや BMI は スーパーユーザーの追加 で追加したユーザーのものに変化しているはずです。

これは、views.pyuser_view で、ログインしたユーザーのニックネームや BMI を表示するようにしているためです。より具体的には、request.userget_short_nameget_bmi のメソッドを実行させているからです。

ログインしたユーザーに応じて表示される情報が変化する様子

こういった動作から、models.py で作成した CustomUser を利用してログインが実現されていることや、CustomUser に定義したメソッドを利用してログインユーザーに応じた情報表示が実現できていることを確認できると思います。

今回示した例は簡単なものになりますが、カスタムユーザーを作り込み、それに合わせてビューやフォームを作成することで、様々なアプリを実現することができることを理解していただけたのではないかと思います!

まとめ

このページでは、Django での「カスタムユーザー」の作り方について解説しました!

カスタムユーザーは AbstractUser を継承することで簡単に作成することが出来ます。

ただし、カスタムユーザーを作成した場合は settings.py での AUTH_USER_MODEL の設定が必要であることに注意してください。

また、アプリ運用開始後に User からカスタムユーザーにモデル自体を変更してしまうとマイグレーションが大変(エラーを解消するのが大変)なので、アプリ開発時はできるだけ早い段階でカスタムユーザーの作成を行なった方が良いと思います。

長々と解説をしましたが、ポイントは開発したいアプリに合わせてカスタムユーザーのフィールドやメソッドを追加すること、さらに、追加したフィールドやメソッドに合わせて管理画面やフォーム・ビューを作成する必要がある点になると思います。

このポイントさえしっかり理解しておけば、カスタムユーザーの作成および利用はそんなに難しくないと思います。

カスタムユーザーを導入すれば、開発できるアプリの幅も広がりますので、是非カスタムユーザーの作り方は覚えておいてください!

また、ページの中でも少し触れたように、AbstractUser ではなく AbstractBaseUser を継承することで、より柔軟にカスタムユーザーを作成することができるようになります。AbstractBaseUser を継承してカスタムユーザーを作成する手順は下記ページで解説していますので、必要に応じてこちらも是非参考にしてください!

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

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

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です