diadia

興味があることをやってみる。自分のメモを残しておきます。

djangoに定期起動する機能を実装する

djangoウェブアプリケーションで表示される情報を定期的に更新したい

現状のプロダクトでは、postgresqlcsvのデータをコピーしただけなのでデータは変更されない。ブログのようなアプリケーションならこれで十分だけれども、定期的に情報を更新したいものには対応できない。例えば、株価、為替、天気のような情報だ。これが問題だった。情報を更新するには何が必要か調べたのでメモしておく。

情報更新に必要な要素

情報収集する際に"django クローン"で調べるといろいろ情報が出てきた。それをもとに必要な要素が確定した。

  • データオブジェクトの更新
  • 更新トリガーを作る
  • 更新する頻度の設定

データオブジェクトの更新

データオブジェクトの更新は、views.pyの中でデータオブジェクトを抽出し、当該オブジェクトのデータを変更して、save()すれば良い。変更内容はスクレイピングなどを利用して更新したい情報を取得する。

更新トリガーを作る

更新トリガーはdjango-admin コマンドの実装を参考にした。 https://docs.djangoproject.com/ja/2.1/howto/custom-management-commands/

python manage.py hogehoge

という自作のコマンドを作成することができ、これによりコマンド入力の際にviews.pyを走らせることができるようになる。

更新する頻度の設定

これはサーバのクローンを利用する。crontabコマンドを使うと定期的に指定した日時で何らかの指示を実行してくれる。

具体的な実装手続き

実装方法には二つ方法がある。一つはdjango-extensionsを使う方法。もう一つはdjango-extensionsを使わない、いわばライブラリに頼らないで実装する方法である。
django-extensionsを使わなくても、それほど実装方法が変わることはないので後者をお勧めする。一応両方のやり方を残しておく。

django-extensionsの採用

djanogo-extensionsを利用するとcommand作成に必要なディレクトリやファイルの構造を自動で作成してくれる。だからviews.pyでどんな挙動にするかを記述することに専念することができる。またこの必要なディレクトリやファイルの構造を自分で作成するのがdjango-extensionsを使わない方法である。

django-extensionsのインストール

こちらを参考にさせていただきました。
https://tokibito.hatenablog.com/entry/20150827/1440602095

$ pip install django-extensions

settings.pyを編集する。注意点はpipインストールしたモジュール名はdjango-extensionsだけれども、追加する内容はdjango_extensionsで異なる。ハイフンとアンダーバーの違いに注意すること。間違うとコマンド作成時に以下のエラーになります。

ModuleNotFoundError: No module named 'django-extensions'

話は戻ってsettings.pyの編集。

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django_extensions',  # この行を追加
)

BaseCommand周りについて

実際にどのような挙動をするかを記述する場所は,management/commands/**.pyである。
ここに好きなように書くのではなく、BaseCommandクラスを継承したCommandクラスを定義する。そして自分の望む挙動を書き込む。

ドキュメント

https://docs.djangoproject.com/ja/2.2/howto/custom-management-commands/#methods
メソッドが重要であるので見てみるとよい。
BaseCommand.add_arguments(parser)メソッドは、python manage.py hogehogeをコマンドとして認識するようにする働きを持ちます。
BaseCommand.handle(*args, **options)メソッドは、python manage.py hogeコマンドが実行されたら、具体的に挙動するかを定める役割を持ちます。

 

自力で行う

django-extensionsを使わない場合はディレクトリ、ファイルを自作するだけである。
その場合はドキュメントをみてディレクトリやファイルの構造をまねて作ればよい。

document: https://docs.djangoproject.com/ja/2.2/howto/custom-management-commands/#module-django.core.management

  • コマンドファイルを適切におくディレクトリ構造を作成
  • Commandクラスを作成するコマンドファイルの作成

コマンドファイルを適切におくディレクトリ構造を作成

apps(アプリディレクトリ)以下に以下のディレクトリを設ける。
management/commands

# mkdir -p management/commands

commands以下に自分が作りたいコマンドを記したコマンドファイルを作成することになる。

Commandクラスを作成するpythonファイルの作成

apps(アプリディレクトリ)/management/commands以下にcron_command.pyを作成する。

from django.core.management.base import BaseCommand
from apps.models import Mymodel   #アプリディレクトリのモデルファイル
import requests 
from bs4 import BeautifulSoup

class Command(BaseCommand):
    

    def add_arguments(self, parser):
        parser.add_argument('hoge')   #このhogepython manage.py hogeのコマンド名になる

    def handle(self, *args, **options):
        url = "https://hogehogehoge"  # handle以下はpython manage.py hogeコマンドが実行されたときに挙動する内容
        res = requests.get(url)
        ...
        ...
        return render(...)
        

Centos7にコマンドを実行させる

 

crontab -e

実行したい時間を定め、ユーザーを指定、コマンドを実行する内容を記録。