django.contrib.auth.models.Userを継承して拡張する
DjangoのUserモデルを拡張したいのでやってみた。
使用したDjangoのバージョンは1.3
継承用のアプリの作成
ここではaccountsというアプリ名に。
python manage.py startapp accounts
auth.models.Userを継承したモデルの作成
マネージャーも変更できるようにauth.models.UserManagerを継承したクラスに変更。
継承したUserモデルには電話番号のfieldを追加してみた。
from django.db import models
from django.contrib.auth.models import UserManager as AuthUserManger, User as AuthUser
class UserManager(AuthUserManger):
pass
class User(AuthUser):
tel = models.SlugField(verbose_name=u'電話番号', max_length=13, blank=True)
#デフォルトのマネージャを変更
objects = UserManager()
認証用バックエンドの作成
先ほど作成したUserモデルで認証できるようにする。
accounts.backends.py
from django.contrib.auth.backends import ModelBackend as Backend
from accounts.models import User
class ModelBackend(Backend):
"""
accounts.models.Userのユーザー認証をするバックエンド
"""
def authenticate(self, username=None, password=None):
try:
user = User.objects.get(username=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
authenticate関数と、get_user関数の戻り値を継承したUserへ変更した関数を作る。
settings.pyに認証バックエンドを設定
AUTHENTICATION_BACKENDS = (
"accounts.backends.ModelBackend",
)
これでOK。 django.contrib.auth.middleware.AuthenticationMiddleware はbackendのauthenticate関数を内部で使用してるので特に変更する必要はなさそう。
せっかくなのでadminでも動くようにする。
django.contrib.auth.admin.UserAdminを継承して動くようにする。
UserAdmin内部で使用するフォームを修正
UserCreationFormとUserChangeFormの使用するmodelを継承したUserモデルに変更する下準備。
account.forms.py
from django.contrib.auth.forms import UserCreationForm as AuthUserCreationForm, UserChangeForm as AuthUserChangeForm
from accounts.models import User
class UserCreationForm(AuthUserCreationForm):
class Meta:
model=User
class UserChangeForm(AuthUserChangeForm):
class Meta:
model=User
作成したUserモデルをMetaクラスにセットしとく
admin.pyの作成
accounts.admin.py
from django.contrib import admin
from django.contrib.auth.models import User as AuthUser
from django.contrib.auth.admin import UserAdmin as AuthUserAdmin
from accounts.models import User
from accounts.forms import UserCreationForm, UserChangeForm
class UserAdmin(AuthUserAdmin):
#さっき作ったフォーム
form = UserChangeForm
#さっき作ったフォーム
add_form = UserCreationForm
#追加した電話番号を更新できるように。
fieldsets = AuthUserAdmin.fieldsets + (('tel', {'fields': ('tel',)}),)
#djangoのデフォルトUserモデルをadminサイトで表示しないように
admin.site.unregister(AuthUser)
#継承して作ったadminフォームを登録
admin.site.register(User, UserAdmin)
adminサイトにDjangoデフォルトのUserモデルは邪魔なので表示しないようにした。別にしなくてもいい。
syncdb時のスーパーユーザー作成コマンドを変更する。
syncdbした時に、superuserを作成していなければDjangoは作成するか聞いてくる。
これを継承したUserモデルに変更する。
スーパーユーザーを作成するコマンドを作成
「createsuperaccount」っていうコマンドを作ることにする。
手っ取り早くコピーしてしまおう。
django.contrib.auth.management.commands.createsuperuser.py
こいつをaccountsディレクトリ以下に配備
accounts.management.commands.createsuperaccount.py
ファイル名はコマンド名になるので注意。
importするUserを変更したらコマンド完成
#from django.contrib.auth.models import User
from accounts.models import User
post_syncdbシグナルを変更
デフォルトのcreate_superuserコマンドを無効化して、作成したcreatesuperaccountコマンドを有効化するシグナルを作成する。
accounts.management
from django.contrib.auth import models as auth_app
from django.db.models import get_models, signals
from django.contrib.auth.management import create_superuser as auth_create_superuser
from accounts import models as accounts_app
def cruser(app, created_models, verbosity, **kwargs):
from django.core.management import call_command
if accounts_app.User in created_models and kwargs.get('interactive', True):
msg = ("\nYou don't have any superusers defined.\nWould you like to create one "
"now? (yes/no): ")
confirm = raw_input(msg)
while 1:
if confirm not in ('yes', 'no'):
confirm = raw_input('Please enter either "yes" or "no": ')
continue
if confirm == 'yes':
call_command("createsuperaccount", interactive=True)
break
# デフォルトのcreate_superuserコマンドを無効化
signals.post_syncdb.disconnect(auth_create_superuser,
sender=auth_app, dispatch_uid = "django.contrib.auth.management.create_superuser")
# 作成したcreate_superuserコマンドを有効化
signals.post_syncdb.connect(cruser,
sender=accounts_app, dispatch_uid = "accounts.management.create_superuser")
これでsyncdbコマンドをコールした時に継承したモデルのスーパーユーザーを作成するか聞いてくる。