Django DB イベントのフックを実装する

シェアする

Django DB イベントのフックを実装します。

DB イベントのフックとは、例えば、特定のテーブルに対してインサートした時に、事前に登録しておいた、コールバック関数を実行するということです。

Django は5年以上使っているのですが、Signals という機能に最近気がつきました。

Signals | Django documentation | Django

覚えていると便利そうですので、どんな感じなのか、実装して動きを見てみたいと思います。

環境とバージョン

  • CentOS 7.5.1804
  • Python 3.6.4
  • Django 2.1.1

インストール

Django DB イベントのフックを実装する環境を構築します。

Python

$ sudo yum install https://centos7.iuscommunity.org/ius-release.rpm
$ sudo yum install python36u python36u-libs python36u-devel python36u-pip

Python3.6 をインストールします。

Django

$ sudo pip install --upgrade django

Django をインストールします。

実装

環境構築が終わったら、次は実装していきます。

プロジェクトとアプリケーションの作成

$ django-admin startproject db_event_hook
$ cd db_event_hook/
$ python3.6 manage.py startapp myapp

実装に入る前に、Django の startproject と startapp コマンドで、プロジェクトとアプリケーションの雛形を作成します。コマンドを実行する場所はどこでもOKです。

settings.py

INSTALLED_APPS = [
    ...
    'myapp.apps.MyappConfig',
]

次に settings.py でプロジェクト全体の設定を行いますが、今回は、INSTALLED_APPS に startapp で作成したアプリケーションを指定するだけです。

models.py

from django.db import models

class MyModel(models.Model):
    col = models.IntegerField()

models に DB を定義します。フック対象とするテーブルです。

apps.py

from django.apps import AppConfig

class MyappConfig(AppConfig):
    name = 'myapp'

    def ready(self):
        from myapp import signals

startapp で作成された apps.py に、これから実装する signals をインポートします。

signals.py

from django.db.models.signals import post_save
from django.dispatch import receiver

from myapp.models import MyModel

@receiver(post_save, sender=MyModel)
def my_model_post_save_event_handler(sender, instance, **kwargs):
    print('my_model_post_save_event_handler!!')

今回のメイン関数 signals.py を作成します。

receiver デコレータに、フックしたいイベントと監視対象のテーブルを指定し、コールバック関数を作成します。今回は、書き込み処理後のイベント (post_save) をフックしています。

動作確認

実装が終わったら、動作確認をします。

DB マイグレーション

$ python3.6 manage.py makemigrations
Migrations for 'myapp':
  myapp/migrations/0001_initial.py
    - Create model MyModel
$ python3.6 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, myapp, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying myapp.0001_initial... OK
  Applying sessions.0001_initial... OK

まずは、DB マイグレーションを行い、models.py の定義を DB に反映します。

Django シェル

$ python3.6 manage.py shell
Python 3.6.4 (default, Dec 19 2017, 14:48:12)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-16)] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from myapp.models import MyModel
>>> MyModel.objects.create(col=1)
my_model_post_save_evnet_handler!!
<MyModel: MyModel object (1)>
>>>

それでは、実際に動作確認していきます。いつもは、デバッグサーバの runserver を起動して、ブラウザからの動作確認ですが、今回は、Django shell を使って、動作確認したいと思います。

Django shell で、フック対象テーブルのレコードを作成(7行目)し、signals.py で実装したコールバック関数が実行される(8行目)のを確認できると思います。

まとめ

Django DB イベントのフック Signals を実装しました。

DB イベントのフックポイントは、他にもたくさん用意されており、様々なシーンで使えそうです。また、Signals は、DB だけでなく、Request のフックポイントや、さらに、独自に Signal を作ることもできそうです。

models.py など、既存ソースコードに手を入れることなく、非同期で処理を追加できるのも便利でいいですね!

シェアする

フォローする