はじめに
弊社が開発・運用・保守している+Auctionでは、pdf帳票生成・メール送信をpythonスクリプトから実行しています
基本的は定期実行なので、cronで運用していますが、スポット的にイレギュラーな場合があり、定期実行から外れることがあります
そういう場合を考慮して、Django Admin(Web)から、実行できるようにしました
帳票生成(メール送信)スクリプトをurlリンクから実行させる、というシンプルな思想です
概要
- ~/project/scriots/bin/create_join_invoice.pyを、~/project/app_name/views.pyにインポートし、CreateJoinInvoiceView()を設定する
- adminにurlリンクを設定し、CreateJoinInvoiceView()を実行する
帳票作成スクリプト
pdfrw、reportlabを使って、pdfを生成しています
他、Taxモデル、os、datetime、settings等importしています
from pdfrw import PdfReader
from pdfrw.buildxobj import pagexobj
from pdfrw.toreportlab import makerl
from reportlab.lib.units import mm
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen import canvas
def main():
# フォントの設定
ttf_file = settings.FONT_PATH
pdfmetrics.registerFont(TTFont('IPAexGothic', ttf_file))
# ファイル生成
cc = canvas.Canvas(file_path + '/' + file_name)
# テンプレート読み込み
page = PdfReader(settings.JOIN_FEE_TEMPLATE_INVOICE_PDF, decompress=False).pages
# 1ページ目をオブジェクトに
pp = pagexobj(page[0])
cc.doForm(makerl(cc, pp))
# 宛先
cc.setFont('IPAexGothic', 16)
target_x, target_y = 20 * mm, 255 * mm
cc.drawString(target_x, target_y, custom_user.company_name) # defaultの描画(左寄せ)
# 合計
cc.setFont('IPAexGothic', 8)
target_x, target_y = 145 * mm, 129 * mm
cc.drawRightString(target_x, target_y, '¥ ' + str('{:,}'.format(join_fee.annual_fee + math.floor(sale_tax))))
# 右よせの描画
#
# 実際はこの部分に、明細、請求元、消費税等があるが、長くなる
# または、importしているので、複雑になることから割愛
#
cc.showPage()
cc.save()
if __name__ == '__main__':
main()
- IPAexGothicのインストール方法は、
IPA Font ダウンロード | 一般社団法人 文字情報技術促進協議会等を参照ください
帳票生成スクリプトをviews.pyにimport
create_join_invoice.pyをapp_name/views.pyにimportし、webから実行できるようにします
from scripts.bin import create_join_invoice
class CreateJoinInvoiceView(SuperuserRequiredMixin, TemplateView) :
def get(self, request, *args, **kwargs):
context = {}
context['back_link'] = '/admin/'+settings.ADMIN_PATH+'/app_name/script'
context['title'] = '年会費(システム利用料)請求書生成スクリプト実行'
context['detail'] = Script.objects.get(pk=self.kwargs['pk'])
run_script = create_join_invoice.main() # create_join_invoice.py内のmain()を呼び出す
context['script'] = run_script
return render(request, 'app_name/invoice/invoice.html', context)
定期実行スクリプト用のmodel
スクリプトファイル名をDBに登録しておきます
DBに登録することで、DjangoのAdminから実行しやすくなります
class Script(BaseModel):
title = models.CharField(verbose_name='タイトル', max_length=50, blank=False, null=False)
detail = models.TextField(verbose_name='詳細・内容', blank=False, null=False)
script_file_name = models.CharField(verbose_name='ファイル名', max_length=50, blank=False, null=False)
run_time = models.CharField(verbose_name='実行日時', max_length=100, blank=False, null=False)
url_link = models.CharField(verbose_name='実行スクリプトへのリンク', max_length=500, blank=True, null=True)
- 共通Modelとして、BaseModelを必ず設定するようにしています
class BaseModel(models.Model):
class Meta:
abstract = True
created = models.DateTimeField(verbose_name='生成日時', auto_now_add=True)
modified = models.DateTimeField(verbose_name='更新日時', auto_now=True)
deleted = models.DateTimeField(verbose_name='削除日時', blank=True, null=True)
url_linkに実行するファイル名を登録することで、後述するリンクを生成しやすくなります
Script ModelのAdmin画面
「スクリプト実行」をクリックすると、「CreateJoinInvoiceView()」から、「create_join_invoice.py」が実行され、帳票が生成される仕組みです
「スクリプト実行」リンクの生成
list_display = ('run_time', 'title', 'script_file_name', 'detail', 'run_script_link')
.....
def run_script_link(self, obj):
if obj.url_link:
return mark_safe(
'<a href="/xxxxxxxxxxxx/'+settings.ADMIN_PATH+'/' + str(obj.url_link) + '/'+str(obj.pk)+'">'+obj.title+'実行</a>'
)
else:
return ''
run_script_link.short_description = 'スクリプト実行'
セキュリテイ対策として、urlに「settings.ADMIN_PATH(32桁の「ランダムな文字列)」を挟んでいます
app_nameアプリケーションのurl.pyより抜粋
path('{obj.url_link}/<int:pk>', CreateJoinInvoice.as_view(), name='create_join_invoice'),
終わりに
昔、CakePHPで同様な処理を行ったことがあり、Djangoでもいけんじゃね?と思い、このような処理にしてみました
帳票出力のサンプルはよく見かけますが、帳票出力+Webから実行の合わせ技はなかなか無いのではと思い、記事にしました
どなたかの参考になれば幸甚です