Pythonメモ torinaブログ

このブログはDjangoとBootstrap4で作成されました
ソースコード

Djangoでcron

プログラミング関連 Django
約309日前 2016年5月25日0:13
Webアプリケーションで、定期的に実行したい処理がある、という状況があります
例えば外部のサイトを1時間おきにスクレイピングしその結果を登録、そして表示する、なんて場合です

今回は
・Djangoのコマンドを作成する
・そのコマンドをcronで定期的に実行する
という流れです

プロジェクト名はtest
アプリケーションはcronとします

また、cronの実行環境はCentos6
プロジェクトへのパスは/usr/webapps/test
となります

test/test/urls.py
from django.conf.urls import include, url,patterns
urlpatterns = [
    url(r'^cron/', include('cron.urls', namespace='cron')),  # 追加する
]


test/test/settings.py
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    "cron",  # 追加する
)




わかりやすくするため、views.pyやテンプレートも作成してみます
test/templates/cron/base.html
<!DOCTYPE html>
<html>
<head lang="ja">
    <meta charset="UTF-8">
    <title>くろん</title>
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>


test/templates/cron/index.html
{% extends "cron/base.html" %}
{% block body %}
<table border="1">
  <thead>
    <tr>
      <th>message</th>
      <th>created_at</th>
      <th>updated_at</th>
    </tr>
  </thead>
  <tbody>
    {% for message in messages %}
      <tr>
        <td>{{ message.message }}</td>
        <td>{{ message.created_at }}</td>
        <td>{{ message.updated_at }}</td>
     </tr>
    {% endfor %}
  </tbody>
</table>
{% endblock %}


test/cron/views.py
from django.shortcuts import render
from .models import Message
 
 
def index(request):
    d = {
        'messages': Message.objects.all(),
    }
    return render(request, 'cron/index.html', d)


test/cron/models.py
from django.db import models
 
class Message(models.Model):
    message = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
 
    def __str__(self):
        return self.message




画面は、このような感じです。わかりやすく一件たしてます


ではコマンドを作成していきます
まずはtest/cronにmanagementというディレクトリを作成



その中に、commandsというディレクトリを作成



最後に、 python manage.py コマンド名
のコメンド名にあたる名前で作成します。今回は、python manage.py makeとしたかったのでmake.pyにしました


make.pyの中身はこうです
from django.core.management.base import BaseCommand
from cron.models import Message
 
class Command(BaseCommand):
 
    def add_arguments(self, parser):
        parser.add_argument('message')
 
 
    def handle(self, *args, **options):
        message = options['message']
        Message(message=message).save()
        print("{0}の追加が完了しました".format(message))



これは引数が入力できるようにしています。つまり、python manage.py make メッセージ
とできるようになります
    def add_arguments(self, parser):
        parser.add_argument('message')



コマンドが実行されたときのメインになる部分です
今回はメッセージを取得し、それを元にMessageモデルを作成しsaveしています
    def handle(self, *args, **options):
        message = options['message']
        Message(message=message).save()
        print("{0}の追加が完了しました".format(message))



使い方はこのようになります



では、これを定期的に実行するようにしましょう
今回の環境はCentOS6です
cronは既に動いているものとします


下記コマンドでcronの編集ができます
crontab -e


下記をを追記
0 * * * * /usr/local/bin/python3.5 /usr/webapps/test/manage.py make 0時です >>/tmp/cron.log 2>>/tmp/cron_error.log



書式は
分 時 日 月 曜日 実行ユーザ 実行コマンド


となっています


これは、毎時0分に実行するという意味です
0 * * * *


0分と30分に実行したいなら、こうです
0,30 * * * *


これはpythonのパスです。virtualenvの場合は、そのパスにしましょう
/usr/local/bin/python3.5


Djangoプロジェクトのパスになります。フルパスにするのを忘れないようにしましょう
/usr/webapps/test/manage.py make 0時です


これはログの設定です。
通常のログを/tmp/cron.logに、エラーのログを/tmp/cron_error.logにしています
ログをメールで送信したり、ログローテーションだとかあるので、詳しい人はやってみるとよいでしょう
 
>>/tmp/cron.log 2>>/tmp/cron_error.log


参考
http://stackoverflow.com/questions/30230490/django-custom-command-error-unrecognized-arguments