PythonでデータレコードをCSV形式に変換・登録

全般

はじめに

こんにちは!

 現在私はPythonとDjangoを使用した案件に携わっております。
 業務で担当となったバッチの作成に「データレコードをCSV形式で生成しそれを他のテーブルのとあるカラムに値に設定する」という処理がありました。私自身ここの処理が上手く実装できずに苦労したので備忘録的な感じで今回投稿します。

筆者について
 高校・大学でプログラミングをかじり、2021年の4月からmiracleaveに入社した新卒2期生です。
入社後は運用保守チームで開発・改修を行い、現在はPythonとDjangoの案件に参画しています。

今回の完成形・ゴール

class CsvDataCreate(BatchLogic):
    # 商品情報をcsv編集登録 

    def __init__(self, *args, **options):
        super().__init__(*args, **options)
        
    @transaction.atomic()
    def handle(self, *args, **options):

            fruit_data = Fruit.object.get(name=apple)
	    csv_info_list = []
	    csv_info_obj = CsvObject()
	    csv_info_list = csv_data_obj.csv_info(self, fruit_data)
	    fruit_info_create = [val for val in csv_info_list.__dict__.values()]

	    fruit_data = store(
	        fruit=','.join(map(str, fruit_info_create))
	    )
	    fruit_data.save()


class CsvObject():

    def __init__(self):
        self.code: str           # 商品コード
        self.name: str           # 商品名
        self.explanation: str    # 商品説明
        self.price: str          # 商品価格
        self.create_at: str      # 作成日時
        self.update_at: str      # 更新日時
        self.create_user: str    # 作成者
        self.update_user: str    # 更新者

    def csv_info(self, fruit_data):
        self.code = fruit_data.code
        self.name = fruit_data.name
        self.explanation = fruit_data.expanation
        self.price = fruit_data.price
        self.create_at = fruit_data.create_at
        self.update_at = fruit_data.update_at
        self.create_user = fruit_data.create_user
        self.update_user = fruit_data.update_user
        return self

 今回の実装のゴールはFruitテーブルの1レコードの各カラムの値をcsv形式の文字列にして、Storeテーブルのfruitのカラムに登録するのがゴールです。下記のテーブルのようなイメージです。

fruitテーブル
idcodenameexplationpricecreate_atupdate_at create_at update_at
1123456apple青森産で凄く甘い10002021/01/01 2021/02/01TaroHanako
2987654bananaエクアドル産で大きい1002021/01/01 2021/02/01HiroshiSatoshi
storeテーブル
idstore_namericebreadfruitwaterbeerice_creamsweet_treat
1東京支店あきたこまち国産もち米123456,”apple”,”青森産で凄く甘い”,1000,”2021-01-01″,”2021-02-01″,”Taro”,”Hanako”南アルプス ドライビールバニラクッキー
2大阪支店玄米メロンパン987654,”banana”,”エクアドル産で大きい”,100,”2021-01-01″,”2021-02-01″,”Hiroshi”,”Satoshi”北アルプス ビール抹茶チョコレート

csv形式データ作成(準備)

class CsvObject():

    def __init__(self):
        self.code: str           # 商品コード
        self.name: str           # 商品名
        self.explanation: str    # 商品説明
        self.price: str          # 商品価格
        self.create_at: str      # 作成日時
        self.update_at: str      # 更新日時
        self.create_user: str    # 作成者
        self.update_user: str    # 更新者

    def csv_info(self, fruit_data):
        self.code = fruit_data.code
        self.name = fruit_data.name
        self.explanation = fruit_data.expanation
        self.price = fruit_data.price
        self.create_at = fruit_data.create_at
        self.update_at = fruit_data.update_at
        self.create_user = fruit_data.create_user
        self.update_user = fruit_data.update_user
        return self

 まずcsv形式で生成するデータ準備段階としてCsvObjectという名前のクラスを宣言します。次にcsv_infoという名前のメソッドを定義し、 fruitテーブルの各カラムに、Storeテーブルのfruitに登録したい値を入れます。

 fruit_dataが不意に登場していますが何者かというと条件を指定して取得したレコードです。こちらは次のところで説明したいと思います。

csv形式データ作成(実行)

class CsvDataCreate(BaseLogic):
    # 商品情報をcsv編集登録 

    def __init__(self, *args, **options):
        super().__init__(*args, **options)
        
    @transaction.atomic()
    def handle(self, *args, **options):

            fruit_data = Fruit.object.get(name=apple)
            csv_info_list = []
	    csv_info_obj = CsvObject()
	    csv_info_list = csv_data_obj.csv_info(self, fruit_data)
	    fruit_info_create = [val for val in csv_info_list.__dict__.values()]

 ここからcsv文字列に変換したいと思います。最初にFruitテーブルの中でcsv形式にしたいレコードを条件を指定し、変数に入れます。今回はappleのレコードを選択したいと思います。このappleのレコードが格納されている変数( fruit_data )が3の csv_info の引数となります。

 次に CsvObject() クラスとその中のメソッドを順々に 変数に入れていきます。そしてその変数( csv_info_list )を for文でぐるぐるまわし fruit_info_create に値を代入していきます。ここでのポイントが __dict__.values() を使用することです。これは簡単にいうと、_dict__属性のvaluesメソッドを使用すれば全プロパティの値だけ取得することができます。このメソッドを使わないと値だけが欲しいのにオブジェクトが返ってきてしまいcsv形式の文字列にはできないないので、ここに注意しましょう。

 またエディターのdebug機能もしくはprint()で fruit_info_createを確認すると以下のようにリストになっていれば成功です

['123456','apple','青森産で凄く甘い','1000','2021-01-01','2021-02-01','Taro','Hanako']


データベース登録

fruit_data = Store(
        fruit=','.join(map(str, fruit_info_create))
)
fruit_data.save()

 ここでStoreテーブルのfruitというカラムに、3と4で準備・実行して生成されたデータをデータベースに登録します。’,’をつけることで、csv形式のコンマ区切りにすることができます。map関数は、map(使用したい関数, 関数を使用したいオブジェクト)という形式で書いていきます。数値を文字列化するstr関数を、オブジェクト fruit_info_create に対して使いたいので、map(str, fruit_info_create )と書き、リストの要素を連結するjoinを使用して連結させましょう。

 最後にfruit_dataをsave()をすればStoreテーブルの東京支店のfruitカラムにcsv形式の文字列が値としてコミットされ、冒頭にお見せしたテーブルのようになります。

一通りの実装はここまでです。お疲れ様でした。

おわりに

 いかがでしたしょうか。ある程度Python/Djangoを経験したエンジニアからしたらもっと良い実装方法であったり、カンタンに実装できる内容だったかもしれないです。ですが私自身はじめにで記載した通り、ここの実装で大変苦労し、自分の知識の無さを痛感させられ心が折れそうになりました…(笑)
 なので今回の記事は初学者向け・駆け出しエンジニア向けということで、少しでも参考になれば幸いです。

コメント