はじめに
こちらの記事の続きになります。
Django管理サイトとは
Djangoには標準で管理サイトが用意されていて、接続しているDBを参照・編集ができたりします。
私的には、この管理サイトが標準で用意されているところがDjangoの良いところだと思ってます。
ルーティング設定ファイル
urls.py
はブラウザから送られるHTTPリクエストに対して、どのページを表示するかというルーティングを記載するファイル。
設定ディレクトリや、アプリケーションディレクトリに作成します。
※設定ディレクトリのurls.pyは自動で作成されますが、アプリケーションディレクトリのurls.pyは手動で作成してあげる必要があります。
(参考)最初にアクセスされるurls.py
settings.py
に書かれています。
以下の例の場合ですと、設定ディレクトリ(config)内のurls.pyを最初にアクセスするという記述になります。
つまり、このurls.pyに記載されているルーティングが優先されます。
ROOT_URLCONF = 'config.urls'
ルーティング設定ファイルの確認
設定ディレクトリに作られるルーティングファイルurls.py
は以下のようになっています。(コメントアウトは省いてます)
注目すべきは、urlpatterns
の部分。
http://{FQDN}:{port}/admin
にアクセスがあったときに、admin.site.urls(Django管理サイト)
を参照するようなルーティングが書かれています。
※初期状態だとDjango管理サイトの設定をしてないのでブラウザでURLを叩いても何も表示されません。
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
アプリケーション作成
Djangoで利用するアプリケーションを作成する。
以下のコマンドでアプリ用のテンプレ構成が作成される。(作られたばかりだと中身スカスカ)
app
は任意のアプリケーション名を設定。
アプリケーションの中にユーザーの設定を書いていく。
# python manage.py startapp app
settings.py
に作成したアプリケーションを追記する。
AUTH_USER_MODEL
の設定も追加。認証用のユーザーモデルには、これから作成するCustomUser
を利用するよ、という記述をしておきます。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
+ 'app',
+
+ AUTH_USER_MODEL = 'app.CustomUser'
カスタムユーザーモデルを作成
Djangoのユーザーモデルには3種類ある。
今回は、AbstractBaseUserを使って作成する。
種類 | カラム操作 | 特徴 |
---|---|---|
User | 不可 | Django標準モデル。Model作成後にカラム追加ができないため、標準の状態で使う。 |
AbstractUser | 追加・変更のみ | カラム追加や変更は可能だが、削除ができないので、使う予定のないカラムが入ってしまう。 |
AbstractBaseUser | 追加・変更・削除 | オリジナルのテーブルが作成可能。好きにカスタマイズできるのはこれ。 |
参考
- AbstractUserモデルは、AbstractBaseUserモデルとPermissionsMixinを継承している。
- Userモデルは、AbstractUserモデルを継承している。
どのように継承されているかは、こちらを参照。
models.py
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager, PermissionsMixin
設定 | 説明 |
---|---|
AbstractBaseUser | AbstractBaseUserを継承してカスタマイズ可能なユーザーモデルを作成する。 |
BaseUserManager | BaseUserManagerを継承してCustomUserManagerクラスを作っている。 |
PermissionsMixin | AbstractBaseUserはパーミッション(権限)関連の機能を持っていないため、パーミッションの機能を利用したい場合、PermissionsMixinを同時に継承しておく必要がある。 |
継承元のコードはこちらから参照できる。
create_user,create_superuser
create_user
や、create_superuser
の作り方は、UserManagerクラスのcreate_user
、create_superuser
メソッドを参考にしている。
from django.utils.translation import gettext_lazy as _
多言語対応(翻訳)させるときに使う。させない場合は不要。
as _
としており、_('ユーザー名は必須です。')
ここで使われている。
なぜアンダーバーなのかというと、Pythonの標準ジュールであるgettext
の慣習的なものなのだそう。
これを使う場合は、settings.py
にUSE_I18N = True
の設定が必要。
if not username:
raise ValueError(_('ユーザー名は必須です。'))
django.utils.translation
には、gettext
とgettext_lazy
があるのだが翻訳が実行されるタイミングが違うらしい。
継承元のコードはこちら。
こちらのAbstractUserを参考にすると、Metaクラスは以下のようになります。
https://github.com/django/django/blob/main/django/contrib/auth/models.py
class Meta:
verbose_name = 'user'
verbose_name_plural = 'users'
abstract = True # これは削除する
abstract = True
は削除してください。python manage.py make migrations
したときにエラーになります。
以下のようなエラーがでます。
django.core.exceptions.ImproperlyConfigured: AUTH_USER_MODEL refers to model 'account.CustomUser' that has not been installed
抽象モデル(クラス)とみなされて実体が作成されず、エラーになるようです。
(参考)こちらのサイトを参考にさせていただきました
https://daeudaeu.com/django-abstractbaseuser/
管理者ページを作成する
admin.py
に以下の記述をします。
このファイルはDjango管理サイトに表示させる内容を記述するファイルになります。
fieldsetsおよびfieldsは、リスト型もしくはタプル型で記述します。
from django.contrib.auth.admin import UserAdmin
from django.contrib import admin
from .models import CustomUser
@admin.register(CustomUser)
class CustomUserAdmin(admin.ModelAdmin):
fieldsets = (
(None, {"fields": ("username", "password")}),
("Personal info", {"fields": ("email",)}),
("Permissions", {"fields": ("is_active", "is_staff", "is_admin", "groups", "user_permissions")}),
("Important dates", {"fields": ("last_login", "date_joined")}),
)
list_display = ("username", 'email', "last_login", 'is_staff')
search_fields = ("username", "email")
filter_horizontal = ("groups", "user_permissions")
DBに反映させる
DBに反映させる内容を作成します。
# python manage.py makemigrations
makemigrations
の最後のsをつけ忘れやすいので注意しましょう。
No changes detectedとか、エラーが出てなさそうな表示がされればOK。
DBに反映させます。
# python manage.py migrate
エラーがでなければOK。
すでにUserモデルを作成している場合、カスタムユーザー作成しようとするとエラーになります。
最初から作り直した方が楽と言われるくらい面倒くさいようなので、DBの中身を作り込む前に、カスタムユーザーモデルだけ作成しておきましょう。
Userモデルを作り直す場合、面倒くさい手順を踏みます。
-
DBの削除(db.sqlite3の場合はファイルごと削除)
-
DB新規作成
(参考)sqlite3のDB作成方法はこちらにまとめてます。
https://qiita.com/Nats72/items/4a420d7a54a0f67aa0cd -
アプリケーションディレクトリにある
migrations
ディレクトリの中の__init__.py
以外を削除
※誤ってmigrationsディレクトリをまるごと削除してしまったら、migrations
ディレクトリを作成し、その中に、__init__.py
を空ファイルで作成します。 -
再度マイグレーションします。
※このとき、./config/settings.py
や、./config/urls.py
のadminに関する部分をコメントアウトしておきます。
INSTALLED_APPS = [
# 'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'account',
]
# from django.contrib import admin
from django.urls import path, include
urlpatterns = [
# path('admin/', admin.site.urls),
path('', include('account.urls')),
]
- コメントアウトを外して、再度
python manage.py migrate
します。
管理者ユーザーの作成
python manage.py createsuperuser
で作成します。
ユーザーを作成しておかないと、後述するDjango管理サイトにログインできないためです。
# python manage.py createsuperuser
ユーザー名: admin
Eメールアドレス: hogehoge@mail.com
Password:
Password (again):
Superuser created successfully.
Django管理サイトにアクセスしてみる
http://localhost:8000/admin/
にアクセスしてみます。※localhostで8000番ポートで公開させている場合
下記のURLにリダイレクトされて、ログインページが表示されると思います。
http://localhost:8000/admin/login/?next=/admin/
先程作成した管理者ユーザーのアカウントでログインします。
ログインできたら成功です。
CSSが適用されていない場合
adminの静的ファイルを集めてきましょう。
# python manage.py collectstatic
参考ページはこちら
ライブラリを追加
後述するルーティングの記載には、path
、include
、re_path
といった関数を使います。
※インポートしないと使えないので、必ずインポートしておきましょう。
from django.contrib import admin
from django.urls import path
+ from django.urls import path, include, re_path
アプリケーションディレクトリのurls.pyを参照させる
設定ディレクトリのurls.pyから、アプリケーションディレクトリのurls.pyを参照させる記述になります。
urlpatternsはリスト型なので、複数記述する場合はカンマで区切ります。
urlpatterns = [
path('', include('app.urls')),
path('sub/', include('app.sub.urls'))
]
path('', include('app.urls'))
は、appディレクトリのurls.pyに、
path('sub/', include('app.sub.urls'))
は、appディレクトリの中にあるsubディレクトリのurls.pyに渡します。
※(参考)アプリケーションディレクトリの中に、子ディレクトリを作ることも可能です
views.pyを参照する
アプリケーションのurls.pyから、views.pyを参照するときに記述します。
設定ディレクトリのurls.pyにも書くことはできると思いますが、アプリケーションディレクトリのurls.pyに書くほうが、どのviews.pyを参照しているか分かりやすいので、アプリケーション側に記述するほうが一般的かなと思います。
urlpatterns = [
path('{パス名}', views.{関数名}, name='{名前}'),
path('{パス名}', views.{クラス名}.as_view(), name='{名前}')
]
nameという引数を書いてますが、これはそのpath()に対する名前を書いています。この引数(name)は記述しなくても動きます。関数名と同じ名前を入れてやればいいんじゃないかなと思います。
(例)views.py
のindex()関数を呼び出す書き方
urlpatterns = [
path('', views.index, name='index'),
path('blog/', views.blog, name='blog'),
]
-
path('', views.index, name='index'),
は、http://{サイト名}/のパスにアクセスがあった際に、views.py
のindex()関数を呼び出します。 -
path('blog/', views.blog, name='blog'),
は、http://{サイト名}/blog/のパスにアクセスがあった際に、views.py
のblog()関数を呼び出します。
URLパターン
パスコンバータを使った記述方法と、re_path()関数を使った記述方法があります。
パスコンバータを使った書き方
int,str,path,slugといったパスコンバータを使えます。
以下に使用例を記載します。
urlpatterns = [
path('', views.index, name='index'),
path('<int>/', views.integer, name='integer'),
path('blog/<int:page>/', views.blogpage, name='blogpage'),
]
-
path('<int>/', views.integer, name='integer')
は、http://{サイト名}/整数/のパスにアクセスがあった際に、views.py
のinteger()関数を呼び出します。 -
path('blog/<int:page>/', views.blogpage, name='blogpage'),
は、http://{サイト名}/blog/整数/のパスにアクセスがあった際に、views.py
のblogpage()関数を呼び出します。その際の整数は、pageという名前の引数で渡されます。
re_path()を使った書き方
正規表現を使って記述できます。
re_path('[0-9]', views.integer, name='integer'),
静的ファイルを扱う
urlpatterns = [
re_path(r'^media/(?P<path>.*)$', serve,{'document_root': settings.MEDIA_ROOT}),
re_path(r'^static/(?P<path>.*)$', serve,{'document_root': settings.STATIC_ROOT}),
]
こうも書ける
from django.conf.urls.static import static
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns += staticfiles_urlpatterns()
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
デバッグモード時のみ扱う場合の書き方
if settings.DEBUG:
from django.conf.urls.static import static
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns += staticfiles_urlpatterns()
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)