Python | Django | バッチ処理の実装方法

2021年9月28日

公開日:2021/9/28

Pythonには,DjangoというWebアプリケーションフレームワークがある.フレームワークのため,Djangoを利用するとWebアプリを通常よりも短時間で開発することが可能になる.

2021/9/25に「OAuth認証を用いたgoogleでのログイン方法」を作成した.当該記事で実装した内容をそのまま引き継いだ上で,本記事では,「バッチ処理の実装方法」を以下4項目にて記す.

  1. 基本1
  2. 基本2
  3. データをファイルに出力方法
  4. 参照

◆実施環境

Python 3.8.8
Django 3.2.3

■バッチ処理の実装方法

  1. 基本1

2021/9/25に作成した「OAuth認証を用いたgoogleでのログイン方法」で利用した"myclassbasedviewslogin"フォルダをVS Codeにて開く.その後,"myaccount"アプリに"management"フォルダを作成し,その中に"commands"フォルダを作成する."commands"フォルダに"mytest.py"を作成する.

“ec_site/myaccount/management/commands/mytest.py"を以下のように編集する.

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    
    def handle(self, *args, **options):
        print('batch process 1')

VS Codeの"View"を開き,"Terminal"をクリックする.VS Codeの下部にターミナルが開くので,”conda activate 仮想環境名”を実行し,仮想環境に移行する(移行方法の詳細はこちら).ターミナルで"cd ec_site"(プロジェクト名)を入力し,ディレクトリを変更する.変更後,”python manage.py mytest”を実行する.以下が出力される.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewslogin\ec_site
>python manage.py mytest
batch process 1 # 以下出力箇所

“ec_site/chem_store/management/commands/chem_store_test.py"を以下のように作成する.

“ec_site/chem_store/management/commands/chem_store_test.py"を以下のように編集する.

from django.core.management.base import BaseCommand

class Command(BaseCommand):

    def handle(self, *args, **options):
        print('batch process for chem_store')

ターミナルを開き,"cd ec_site"(プロジェクト名)のディレクトリで”python manage.py chem_store_test”を実行する.以下が出力される.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewslogin\ec_site
>python manage.py chem_store_test

batch process for chem_store # 以下出力箇所
  1. 基本2

“ec_site/myaccount/management/commands/mytest.py"を以下のように編集する.

from django.core.management.base import BaseCommand

class Command(BaseCommand):

    def add_arguments(self, parser):
        parser.add_argument('name')
        parser.add_argument('birthplace')

    def handle(self, *args, **options):
        name = options['name']
        birthplace = options['birthplace']
        print(f'name = {name}, birthplace = {birthplace}')

ターミナルを開き,"cd ec_site"(プロジェクト名)のディレクトリで”python manage.py mytest Jotaro Japan”を実行する.以下が出力される.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewslogin\ec_site
>python manage.py mytest Jotaro Japan
name = Jotaro, birthplace = Japan # 以下出力箇所

“ec_site/myaccount/management/commands/mytest.py"を以下のように編集する.

from django.core.management.base import BaseCommand

class Command(BaseCommand):

    def add_arguments(self, parser):
        parser.add_argument('name')
        parser.add_argument('birthplace')
        parser.add_argument('--job') # 追加箇所

    def handle(self, *args, **options):
        name = options['name']
        birthplace = options['birthplace']
        job = options['job'] # 追加箇所
        print(f'name = {name}, birthplace = {birthplace}, job = {job}') # 変更箇所

ターミナルを開き,"cd ec_site"(プロジェクト名)のディレクトリで”python manage.py mytest Jotaro Japan –job oceanologist”を実行する.以下が出力される.

(djangoenv) C:\Users\shiro\Desktop\210517_pythhon development\myclassbasedviewslogin\ec_sit>e>
python manage.py mytest Jotaro Japan --job oceanologist
name = Jotaro, birthplace = Japan, job = oceanologist # 以下出力箇所

“name"や"birthplace"の型を特定するため,"ec_site/myaccount/management/commands/mytest.py"を以下のように編集する.

from django.core.management.base import BaseCommand

class Command(BaseCommand):

    def add_arguments(self, parser):
        parser.add_argument('name', type=str) # 変更箇所
        parser.add_argument('birthplace', type=str) # 変更箇所
        parser.add_argument('--job')

    def handle(self, *args, **options):
        name = options['name']
        birthplace = options['birthplace']
        job = options['job']
        print(type(name), type(birthplace)) # 追記箇所
        print(f'name = {name}, birthplace = {birthplace}, job = {job}')

ターミナルで”python manage.py mytest Jotaro Japan –job oceanologist”を実行する.以下が出力される."name"や"birthplace"の型がどちらも"str"であることがわかる.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewslogin\ec_site>python manage.py mytest Jotaro Japan --job oceanologist

<class 'str'> <class 'str'> # 以下出力箇所
name = Jotaro, birthplace = Japan, job = oceanologist

“help"によって情報を表示させるため,"ec_site/myaccount/management/commands/mytest.py"を以下のように編集する.

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help='This is batch for expressing user information!'# 追加箇所

    def add_arguments(self, parser):
        parser.add_argument('name', type=str, help='名前を記載する') # 変更箇所
        parser.add_argument('birthplace', type=str, help='出身地を記載する') # 変更箇所
        parser.add_argument('--job')

    def handle(self, *args, **options):
        name = options['name']
        birthplace = options['birthplace']
        job = options['job']
        print(type(name), type(birthplace))
        print(f'name = {name}, birthplace = {birthplace}, job = {job}')

ターミナルで”python manage.py help mytest”を実行する.以下が出力される.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewslogin\ec_site
>python manage.py help mytest
usage: manage.py mytest [-h] [--job JOB] [--version] [-v {0,1,2,3}] # 以下出力箇所
                        [--settings SETTINGS] [--pythonpath PYTHONPATH]   
                        [--traceback] [--no-color] [--force-color]        
                        [--skip-checks]
                        name birthplace

This is batch for expressing user information!

positional arguments:
  name                  名前を記載する
  birthplace            出身地を記載する

optional arguments:
  -h, --help            show this help message and exit
  --job JOB
  --version             show program's version number and exit
  -v {0,1,2,3}, --verbosity {0,1,2,3}
                        Verbosity level; 0=minimal output, 1=normal       
                        output, 2=verbose output, 3=very verbose output   
  --settings SETTINGS   The Python path to a settings module, e.g.        
                        "myproject.settings.main". If this isn't
                        provided, the DJANGO_SETTINGS_MODULE environment  
                        variable will be used.
  --pythonpath PYTHONPATH
                        A directory to add to the Python path, e.g.       
                        "/home/djangoprojects/myproject".
  --traceback           Raise on CommandError exceptions
  --no-color            Don't colorize the command output.
  --force-color         Force colorization of the command output.
  --skip-checks         Skip system checks.

“default"により情報を表示させるため,"ec_site/myaccount/management/commands/mytest.py"を以下のように編集する.

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help='This is batch for expressing user information!'

    def add_arguments(self, parser):
        parser.add_argument('name', type=str, help='名前を記載する')
        parser.add_argument('birthplace', type=str, help='出身地を記載する')
        parser.add_argument('--job', default='lawyer') # 変更箇所

    def handle(self, *args, **options):
        name = options['name']
        birthplace = options['birthplace']
        job = options['job']
        print(type(name), type(birthplace))
        print(f'name = {name}, birthplace = {birthplace}, job = {job}')

ターミナルで”python manage.py mytest Jotaro Japan”を実行する.以下が出力される."job"はデフォルトである"lawyer"が出力されていることがわかる.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewslogin\ec_site
>python manage.py mytest Jotaro Japan

<class 'str'> <class 'str'> # 以下出力箇所
name = Jotaro, birthplace = Japan, job = lawyer

複数の単語を出力させるため,"ec_site/myaccount/management/commands/mytest.py"を以下のように編集する.

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help='This is batch for expressing user information!'

    def add_arguments(self, parser):
        parser.add_argument('name', type=str, help='名前を記載する')
        parser.add_argument('birthplace', type=str, help='出身地を記載する')
        parser.add_argument('--job', default='lawyer')
        parser.add_argument('five_words', nargs=5) # 追記箇所

    def handle(self, *args, **options):
        name = options['name']
        birthplace = options['birthplace']
        job = options['job']
        five_words = options['five_words'] # 追記箇所
        print(
            f'name = {name}, birthplace = {birthplace}, job = {job}, five_words = {five_words}'
        )

ターミナルで”python manage.py mytest Jotaro Japan a b c d e”を実行する.以下が出力される.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewslogin\ec_site
>python manage.py mytest Jotaro Japan a b c d e

name = Jotaro, birthplace = Japan, job = lawyer, five_words = ['a', 'b', 'c', 'd', 'e'] # 以下出力箇所

“True" or “False"を出力させるため,"ec_site/myaccount/management/commands/mytest.py"を以下のように編集する.

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help='This is batch for expressing user information!'

    def add_arguments(self, parser):
        parser.add_argument('name', type=str, help='名前を記載する')
        parser.add_argument('birthplace', type=str, help='出身地を記載する')
        parser.add_argument('--job', default='lawyer')
        parser.add_argument('five_words', nargs=5)
        parser.add_argument('--act', action='store_true') # 追記箇所

    def handle(self, *args, **options):
        name = options['name']
        birthplace = options['birthplace']
        job = options['job']
        five_words = options['five_words']
        act = options['act'] # 追記箇所
        print(
            f'name = {name}, birthplace = {birthplace}, job = {job}, five_words = {five_words}'
        )
        print(act) # 追記箇所

ターミナルで”python manage.py mytest Jotaro Japan a b c d e –act”を実行する.以下が出力される.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewslogin\ec_site
>python manage.py mytest Jotaro Japan a b c d e --act

name = Jotaro, birthplace = Japan, job = lawyer, five_words = ['a', 'b', 'c', 'd', 'e'] # 出力箇所
True

“choose"による選択での出力をするため,"ec_site/myaccount/management/commands/mytest.py"を以下のように編集する.

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help='This is batch for expressing user information!'

    def add_arguments(self, parser):
        parser.add_argument('name', type=str, help='名前を記載する')
        parser.add_argument('birthplace', type=str, help='出身地を記載する')
        parser.add_argument('--job', default='lawyer')
        parser.add_argument('five_words', nargs=5)
        parser.add_argument('--act', action='store_true')
        parser.add_argument('--choose', choices=['Morning', 'Afternoon', 'Evening']) # 追記箇所

    def handle(self, *args, **options):
        name = options['name']
        birthplace = options['birthplace']
        job = options['job']
        five_words = options['five_words']
        act = options['act']
        print(
            f'name = {name}, birthplace = {birthplace}, job = {job}, five_words = {five_words}'
        )
        print(act) # 以下追記箇所
        choose = options['choose']
        if choose == 'Morning':
            print('Good Morning')
        elif choose == 'Afternoon':
            print('Good Afternoon')
        elif choose == 'Evening':
            print('Good Evening')

ターミナルで”python manage.py mytest Jotaro Japan a b c d e –choose Evening”を実行する.以下が出力される.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewslogin\ec_site
>python manage.py mytest Jotaro Japan a b c d e --choose Evening
name = Jotaro, birthplace = Japan, job = lawyer, five_words = ['a', 'b', 'c', 'd', 'e'] # 以下出力箇所
False
Good Evening
  1. データをファイルに出力方法

“ec_site/chem_store/management/commands"に"order_data.py"を以下のように作成する.

“ec_site/chem_store/management/commands/order_data.py"を以下のように編集する.

from django.core.management.base import BaseCommand
from chem_store.models import Orders
from ec_site.settings import BASE_DIR
from datetime import datetime
import os
import csv

class Command(BaseCommand):

    def handle(self, *args, **options):
        orders = Orders.objects.all()
        file_path = os.path.join(BASE_DIR, 'export', 'orders', f'orders_{datetime.now().strftime("%Y%m%d%H%S")}')
        with open(file_path, mode='w', newline='\n', encoding='utf-8') as csvfile:
            fieldnames = ['id', 'user', 'address', 'total_price']
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
            writer.writeheader()
            for order in orders:
                writer.writerow({
                    'id': order.id,
                    'user': order.user,
                    'address': order.address,
                    'total_price': order.total_price,
                })

“ec_site/chem_store/management/commands/order_data.py"に"export"と"orders"を記載したので,"ec_site"に"export"フォルダを作成し,その中に"orders"フォルダを以下のように作成する.

出力されるファイルデータを事前に確認する.そのため,VS Codeにて,SQLiteをインストールし(詳細はこちら参照),"SQLITE EXPLORER"を開く.以下赤枠のorderテーブルを右クリックし,"Show Table"をクリックする.

“Show Table"の中には以下データを確認できる.

ターミナルを開き,"cd ec_site"(プロジェクト名)のディレクトリで”python manage.py order_data”を以下のように実行する.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewslogin\ec_site
>python manage.py order_data

ターミナルにて上記を実行後,"ec_site/export/orders"には以下が出力される.

“ec_site/export/orders/orders_202109280101″には以下内容が記述されている.

id,user,address,total_price
1,josuke@email.com,340-0000 埼玉県 越谷市 abc street xxx,2000
2,josuke@email.com,340-0000 埼玉県 越谷市 abc street xxx,3000
3,josuke@email.com,340-0000 埼玉県 越谷市 abc street xxx,3000

ユーザーごとにファイルを出力させるため,"ec_site/chem_store/management/commands/order_data.py"に追記し,以下のように編集する.

from django.core.management.base import BaseCommand
from chem_store.models import Orders
from ec_site.settings import BASE_DIR
from datetime import datetime
import os
import csv

class Command(BaseCommand):

    def add_arguments(self, parser): # 追記箇所(以下2行)
        parser.add_argument('--user_id', default='all')

    def handle(self, *args, **options):
        orders = Orders.objects.all()
        user_id = options['user_id'] # 追記箇所(以下5行)
        if user_id == 'all':
            orders = orders.all()
        else:
            orders = orders.filter(user_id=user_id)
        file_path = os.path.join(BASE_DIR, 'export', 'orders', f'orders_{datetime.now().strftime("%Y%m%d%H%M%S")}') # 変更箇所("%M"追記)
        with open(file_path, mode='w', newline='\n', encoding='utf-8') as csvfile:
            fieldnames = ['id', 'user', 'address', 'total_price']
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
            writer.writeheader()
            for order in orders:
                writer.writerow({
                    'id': order.id,
                    'user': order.user,
                    'address': order.address,
                    'total_price': order.total_price,
                })

ターミナルを開き,”python manage.py order_data –user_id 1”を以下のように実行する.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewslogin\ec_site
>python manage.py order_data --user_id 1

“ec_site/export/orders"に以下のようにファイルが出力される.

“ec_site/export/orders/orders_20210928022748″には以下データが出力されている.user_idが1のオーダー情報はないので,以下データの出力となる.

id,user,address,total_price

ターミナルを開き,”python manage.py order_data –user_id 2”を以下のように実行する.

(djangoenv) C:\Users\shiro\Desktop\210517_python development\myclassbasedviewslogin\ec_site
>python manage.py order_data --user_id 2

“ec_site/export/orders"に以下のようにファイルが出力される.

“ec_site/export/orders/orders_20210928022852″には以下データが出力されている.user_idが2のオーダー情報は以下データの出力となる.

id,user,address,total_price
1,josuke@email.com,340-0000 埼玉県 越谷市 abc street xxx,2000
2,josuke@email.com,340-0000 埼玉県 越谷市 abc street xxx,3000
3,josuke@email.com,340-0000 埼玉県 越谷市 abc street xxx,3000
  1. 参照

https://docs.djangoproject.com/ja/3.1/howto/custom-management-commands/

以上