批处理应用程序(Django)
首先
我会描述使用Django创建批处理应用程序的步骤。本次示例应用程序已在GitHub上公开。
前提条件
请参考README文件以了解操作环境、设置和批处理应用程序的启动步骤。
Django 是什么
Django(强哥)是用Python实现的Web应用程序框架,它包含了一般Web应用程序开发所需的所有功能。更多详情请参阅Django文档。
通过使用Django丰富的功能,你也可以创建批处理应用程序。
批处理应用程序(django)
我将以Django为基础来解释以下内容。
应用程序配置

设定信息
数据库连接信息、日志级别等在yml文件和django的settings.py文件中进行定义。这些可以根据操作系统和主机名进行更改,因为需要在开发/生产环境之间切换。

設定信息的定義
在开发/正式环境下发生改变的设置值要在yml文件中定义。
在django中,将设置值的定义放在settings.py中。
摘录了在django中添加或修改的默认部分。
# DBの接続情報を設定する
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': AppConfig.get_properties("database_name"),
'USER': AppConfig.get_properties("database_user"),
'PASSWORD': AppConfig.get_properties("database_password"),
'HOST': AppConfig.get_properties("database_host"),
'PORT': AppConfig.get_properties("database_port"),
'OPTIONS': {
'charset': 'utf8mb4'
},
'TEST': {
'NAME': AppConfig.get_properties("test_database_name"),
}
}
}
# Localeのパス設定を行う
LOCALE_PATHS = (
os.path.join(BASE_DIR, 'locale'),
)
# loggingの設定を行う
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'consoleHandler': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'customFormatter'
},
'fileRotatingHandler': {
'level': 'DEBUG',
'class': 'logging.handlers.TimedRotatingFileHandler',
'formatter': 'customFormatter',
'filename': AppConfig.get_log_file(),
'encoding': 'utf8',
'when': 'D',
'interval': 1,
'backupCount': 7
}
},
'formatters': {
'customFormatter': {
'format': '[%(asctime)s] %(levelname)s - %(filename)s#%(funcName)s:%(lineno)d: %(message)s',
'datefmt': '%Y/%m/%d %H:%M:%S',
},
},
'loggers': {
'': {
'handlers': ['consoleHandler', 'fileRotatingHandler'],
'level': AppConfig.get_properties("app_log_level"),
'propagate': False,
},
'django.db.backends': {
'handlers': ['consoleHandler'],
'level': AppConfig.get_properties("sql_log_level"),
'propagate': False,
}
}
}
取得设定信息
根据开发或者正式环境获取相应的配置值,并进行切换以下的配置信息。
環境OSログレベル開発WindowsDEBUG本番LinuxINFO
应用配置
# coding:utf-8
import os
import socket
import yaml
"""
アプリケーションの設定を制御する
"""
class AppConfig:
@staticmethod
def get_properties(key):
"""
設定ファイルからキーに紐づく値を取得する
"""
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
resource_file = base_dir + "/resource/application_" + AppConfig.get_application_config() + ".yml"
with open(os.path.join(resource_file), 'r', encoding='UTF-8') as f:
config = f.read()
return yaml.load(config)[key]
@staticmethod
def get_log_file():
"""
設定ファイルからキーに紐づく値を取得する
"""
return os.path.join(AppConfig.get_properties("log_path"), AppConfig.get_properties("log_file"))
@staticmethod
def get_application_config():
"""
OS情報やホスト名から設定ファイルの読み込み先を取得する
"""
application_config = "develop"
# 実行環境に応じて設定ファイルの読み込み先を切り替える
# Linux またはホスト名で判定しています
if os.name == 'posix' or socket.gethostname() == 'example.com':
application_config = "production"
return application_config
使用下列方法来适当地判别执行环境。
タイプOS値os.namewindowsntlinux or macposixplatform.systemwindowsWindowslinuxLinuxmacDarwin
批处理执行
用命令来运行批处理应用程序。
python /home/pypeach_django/manage.py batch_main create_employees
批量启动
继承django的BaseCommand类并定义批处理启动类,通过指定多个参数,实现灵活的批处理启动。
命令
import gettext
import logging
from django.core.management.base import BaseCommand
from django.db import ProgrammingError
from django.utils.translation import gettext
from app_pypeach_django.application.service.employees_service import EmployeesService
"""
BaseCommandを継承したバッチ起動クラスです。
"""
class Command(BaseCommand):
def add_arguments(self, parser):
"""
引数をセットする
"""
parser.add_argument('parameter', nargs='+', type=str)
def handle(self, *args, **options):
"""
コマンド実行時のハンドラ。
引数に応じて各サービスを実行する
"""
execute_batch = None
for index, parameter in enumerate(options['parameter']):
if index == 0:
execute_batch = parameter
logging.info(gettext("I900"), execute_batch)
try:
if execute_batch == 'create_employees':
EmployeesService.create_employees()
elif execute_batch == 'create_departments':
EmployeesService.create_departments()
elif execute_batch == 'update_employees':
EmployeesService.update_employees()
elif execute_batch == 'select_employees':
EmployeesService.select_employees()
elif execute_batch == 'truncate_employees':
EmployeesService.truncate_employees()
elif execute_batch == 'create_scrapy_html':
ScrapyService.create_scrapy_html()
elif execute_batch == 'parse_scrapy_html':
ScrapyService.parse_scrapy_html()
else:
logging.info(gettext("E902"), execute_batch)
except ProgrammingError as e:
logging.exception(gettext("E903"), e)
except Exception as e:
logging.exception(gettext("E990"), e)
logging.info(gettext("I901"), execute_batch)
提供服务
从批处理启动类执行服务。我使用模型(models)对数据库进行select、insert和update的操作来演示。
员工服务
from django.db import transaction, connection
from django.utils import timezone
from django.utils.timezone import localtime
from app_pypeach_django.application.enums.department_type import DepartmentType
from app_pypeach_django.application.enums.gender_type import GenderType
from app_pypeach_django.application.service.app_logic_base import AppLogicBaseService
from app_pypeach_django.models import Employees, Departments
"""
employeesを操作するクラスです。
"""
class EmployeesService(AppLogicBaseService):
def __init__(self):
super().__init__()
@staticmethod
@transaction.atomic()
def create_employees():
"""
Employeesを作成する
"""
service = EmployeesService()
for emp_no in range(1, 11):
if Employees.objects.filter(emp_no=emp_no, delete_flag=0).count() == 0:
if emp_no <= 5:
department_no = DepartmentType.SALES.value
else:
department_no = DepartmentType.MARKETING.value
select_model = Departments.objects.filter(department_no=department_no).values("id").first()
# データを登録する
service._regist_employees(select_model['id'], emp_no)
def _regist_employees(self, department_no, emp_no):
"""
employeesを登録する
"""
self.regist_model = Employees()
self.regist_model.emp_no = emp_no
self.regist_model.department_no = department_no
self.regist_model.gender = GenderType.MAN.value
self.regist_model.department_date_from = "20190902"
self.regist_model.delete_flag = 0
self.regist_model.regist_dt = localtime(timezone.now())
self.regist_model.update_dt = localtime(timezone.now())
self.regist_model.save()
return self.regist_model.id
关于服务的特别事项如下
- トランザクション制御
为了在处理异常终止时执行回滚操作,请指定@transaction.atomic()。
有关详细信息,请参考Django数据库事务。
信息 (Messa-ji)

消息定义
将消息的ID和文本设置到本地化文件中。
django.po :英文 ,汉化为 “Django.汉密”
msgid "I900"
msgstr "処理を開始します:%s"
msgid "I901"
msgstr "処理を終了します:%s"
msgid "I902"
msgstr "トレース情報:%s"
一旦定义了消息,就可以使用django-admin命令编译。
django-admin compilemessages -l ja
获取消息
使用gettext获取消息。
logging.info(gettext("I900"), execute_batch)
请提供一些参考资料
-
- Djangoドキュメント
- Djangoロケールファイル