Djangoのマイグレーション時にPermissionにアクセスする方法をまとめます。
実行環境
- Django 3.2
マイグレーションファイルの作成
空のマイグレーションファイルを作成します。
python manage.py makemigrations --empty yourappname
from django.db import migrations class Migration(migrations.Migration): dependencies = [ ('yourappname', '0001_initial'), ] operations = [ ]
RunPythonでPermissionにアクセス
RunPythonの第1引数に与えた access_perm
でPermissionにアクセスする状況を想定します。
ここではデフォルトで作成される auth.view_user
の取得を試みます。
from django.db import migrations def access_perm(apps, schema_editor): Permission = apps.get_model('auth', 'Permission') Permission.objects.get( codename='view_user', content_type__app_label='auth' ) class Migration(migrations.Migration): dependencies = [ ... ] operations = [ migrations.RunPython(access_perm), ]
しかし、このコードは以下のエラーを出力します。
Permission.DoesNotExist: Permission matching query does not exist.
これはmigrateの最後に送信されるpost_migrateシグナルがDefault permissionsを作成するためです。
...it will create default permissions for new models each time you run manage.py migrate (the function that creates permissions is connected to the post_migrate signal).
post_migrateシグナルの明示的な送信
ということで、django.core.management.sql.emit_post_migrate_signal(verbosity, interactive, db)
で post_migrate
シグナルを送信することでPermissionを作成します。
第3引数のデータベース名はSchemaEditor.connection.aliasから取得してますが、1つしかデータベースがないなら 'default'
固定でも良いです。
from django.core.management.sql import emit_post_migrate_signal def access_perm(apps, schema_editor): db_alias = schema_editor.connection.alias emit_post_migrate_signal(2, False, db_alias) Permission = apps.get_model('auth', 'Permission') Permission.objects.get( codename='view_user', content_type__app_label='auth' )
これでマイグレーションの途中でPermissionが作成され、参照できるようになりました。
$ ./manage.py migrate ... Running migrations: ... Applying yourappname.yourmigrationfile...Running post-migrate handlers for application admin Adding content type 'admin | logentry' Adding permission 'admin | log entry | Can add log entry' Adding permission 'admin | log entry | Can change log entry' Adding permission 'admin | log entry | Can delete log entry' Adding permission 'admin | log entry | Can view log entry' Running post-migrate handlers for application auth ... Adding permission 'auth | user | Can view user' ...
ただし、他のアプリの post_migrate
を実行してしまうため、 emit_post_migrate_signal
を実行した段階で存在しないテーブルを参照しようとしてしまう場合があり、完全に安全な方法ではなさそうです。このあたりのチケットでもう少しシンプルに扱えるようになると嬉しいものです。
(そもそもMigration Operationで頑張らずにpost_migrateシグナルで実装すれば良い気がする。)