読者です 読者をやめる 読者になる 読者になる

日に日に分からんことが増えていく…

プログラマー初心者としての日々を学んでいることを記録していく。

Djangoの大量のモデル作成方法

概要

  1. model.pyのクラス名とクラス変数をそれぞれcsvファイルにする。
  2. $ python mkmodel_django.py models/クラス名.csvをする。 完成。

csvファイルの作成

クラス名.cvs

オブジェクト名 オブジェクトの説明 備考
OBJECT_NAME 説明〜 備考〜

OBJECT_NAME.csv

項目名 型名 長さ 少数 必須 主キー verbose名
KOMOKU_NAME NUMBER 13 0 Y 1 項目の名前

自動変換

./にmkmodel_django.pyをおき、./models/に作成したcsvファイルを全部つぎ込む。
$ python mkmodel_django.py models/クラス名.csvをすると、/tmp/_model.pyができる。
Clickがなければ$ pip install click

# coding:utf-8
import csv
import codecs
import os
import click
import unicodedata
import tempfile
import stat
import shutil

# Djangoのモデル作成に際し、一括で行うファイル
# python mkmodel_django.py "/modeltitle.csv" "/tmp/_model.py(例)"
# モデルクラス名をcsvファイル名にすると自動で、変数も登録する
# --models-
#
#


def mkmodel_contents_django(fpath):
    f = codecs.open(fpath, 'rU',)
    format_str = "    %s"
    int_str = format_str % (
        "{col} = models.IntegerField({name}, null=True,{addition})")
    float_str = format_str % (
        "{col} = models.FloatField({name}, null=True,{addition})")
    str_str = format_str % (
        "{col} = models.CharField({name}, max_length={length},"
        + " null=True,{addition})"
        )
    date_str = format_str % (
        "{col} = models.DateTimeField({name}, null=True,{addition})")
    clob_str = format_str % (
        "{col} = models.TextField({name}, null=True,{addition})")

    try:
        reader = csv.reader((line.replace('\0', '') for line in f))
        contents = ""
        n = 0
        primary = set()

        for row in reader:
            row = [i.strip() for i in row]
            row[0] = row[0].lower()
            a = ""
            if "\n" in row[6]:
                row[6] = row[6].split("\n")[0]
            if len(row[6]) > 30:
                row[6] = row[6].split()[0]
            if row[5] != "":
                if n == 0:
                    a += " primary_key=True,"
                n += 1
                primary |= {row[0]}
            if row[4] != "":
                a += " required=True,"
            row[6] = unicodedata.normalize(
                'NFKC', (row[6]).decode("utf-8")).encode("utf-8")
            if "NUMBER" in row[1]:
                if not row[3].isdigit():
                    contents += int_str.format(
                        col=row[0],
                        name="u\"%s\"" % row[6],
                        addition=a
                        )
                elif int(row[3]) > 0:
                    contents += float_str.format(
                        col=row[0],
                        name="u\"%s\"" % row[6],
                        addition=a
                        )
                elif int(row[2]) < 10:
                    contents += int_str.format(
                        col=row[0],
                        name="u\"%s\"" % row[6],
                        addition=a
                        )
                else:
                    contents += str_str.format(
                        col=row[0],
                        name="u\"%s\"" % row[6],
                        length=row[2],
                        addition=a
                        )
            elif "CLOB" in row[1]:
                contents += clob_str.format(
                    col=row[0],
                    name="u\"%s\"" % row[6],
                    addition=a
                    )
            elif "DATE" in row[1]:
                contents += date_str.format(
                    col=row[0],
                    name="u\"%s\"" % row[6],
                    addition=a
                    )
            else:
                contents += str_str.format(
                    col=row[0],
                    name="u\"%s\"" % row[6],
                    length=row[2],
                    addition=a
                    )
            contents += "\n"

        if n > 1:
            metastr = "\n    class Meta:\n            unique_together = ((\n" + \
                "                %s\n            ),)" % (
                    ", ".join("\'%s\'" % i for i in list(primary))
                    )

            contents += metastr + "\n"
        return contents + "\n"
    finally:
        f.close()


def mkmodel_django(modelf, modelfile):
    fd, temp = tempfile.mkstemp()
    os.close(fd)
    os.chmod(temp, stat.S_IRWXU | stat.S_IROTH)
    fd = codecs.open(temp, "wb", "utf-8")
    fd.write(
        "# -*- coding: utf-8 -*-\n\nfrom django.db import models\n# Create your models here.\n\n\n"
        )

    f = codecs.open(modelf, 'rU',)
    try:
        reader = csv.reader(f)
        for row in reader:
            contents = "class %s(models.Model):\n\n\tu\'\'\'%s\'\'\'\n\t# %s\n\n" % (
                    "".join(
                        [i.capitalize() for i in row[0].strip().split("_")]
                        ),
                    unicodedata.normalize(
                        'NFKC', (
                            row[1].strip()).decode("utf-8")).encode("utf-8"),
                    unicodedata.normalize(
                        'NFKC', (
                            row[2].strip()).decode("utf-8")).encode("utf-8"),)
            fpath = os.path.join(os.getcwd(), "models", row[0]+".csv")
            if os.path.exists(fpath):
                contents += mkmodel_contents_django(fpath)
            else:
                pass
            contents += "\n"
            fd.write(contents.decode("utf-8"))
        shutil.move(temp, modelfile)
    except Exception as e1:
        print e1
        if os.path.exists(temp):
            os.remove(temp)
    finally:
        f.close()
        fd.close()


@click.command()
@click.argument('modelf')
@click.option('-m', '--model', default=u"/tmp/_model.py")
def cmd(modelf, model):
    mkmodel_django(modelf, model)


def main():
    cmd()


if __name__ == '__main__':
    main()