フォーム定義を扱うクラス

d:id:imait:20090310:1236691433で触れていたテーブル定義を扱うクラスは、めでたくフォーム定義を扱うクラスとして生まれ変わりました。TableDefinitionからFormDefinitionになって、けど内容はそんなに違ってません。

変更点は、クラスやメソッドの名前が変わったり、今まで、変数がNoneであるかを調べるのに、val == None / val != Noneとしていたのを、それは相応わしい方法ではないと知ったので、val is None = val is not Noneというように書き換えたり、このへんは瑣末な変更ですね。

フォーム定義をおさめるテーブルに、ひとつカラムを増やしました。その定義データが作られた日時を記録するcreated_dateを加えて、これはなんというか、ソートに使うためのデータですね。また、今まで日付けはdatetime型をpickle化してbase64でテキストにして保存するようにしてたのですが、それだとソートできないので、strftime('%Y-%m-%d %H:%M:%S')とやって、文字列として保存することにしました。開始日、終了日は秒までいらなかったと思うけど、作成日はミリ秒まで保存したかったので、isoformat()を使いました。

こうしてテキストで保存した日付けデータを取り出す時は、ちゃんとdatetime型に戻すようにもしました。こうすると、なにかと便利です。

あとは、以前はrandom.random()でいいかげんに生成していたIDを、乱数をもとにSHA512でハッシュを作って、hexdigest()で文字列化、その先頭数文字を切り取るというやりかたで生成するようにしました。_generate_id(digit)というメソッドを作って、digitに設定した長さの文字列を返すようにしました。デフォルトは8文字だけど、必要に応じて、長くも短くもできます。

他には、FormDefinitionをはなれて、os.environ.get('REQUEST_METHOD', '')で得られた値がPOSTの場合のみ更新するとか、そういう下調べをしてた、くらいでしょうか。けど、たったこれだけしかやってないのに、一日は終わってしまいます。時間というのは、本当にあっという間に過ぎてしまいます。

# -*- coding: utf-8 -*-
'''
Class form definition
'''

import hashlib
import random
import sys
import sqlite3
import pickle
import base64
import datetime

class FormDefinition:
    '''Class of form definition'''

    def __init__(self, dbpath):
        self.dbpath = dbpath
        self.dbformdefinition = u'formdefinition'
        self.dbitemdefinition = u'itemdefinition'

        connection = self._open_db()
        cursor = connection.cursor()
        cursor.execute('select * from sqlite_master \
        where type=\'table\' and name=\'%s\';' % \
                       self.dbformdefinition)
        tablecount = cursor.fetchall()
        if len(tablecount) == 0:
            cursor.execute('create table %s (fid primary key, title, \
            abbr_title, summary, start_date, end_date, created_date, \
            active);' % \
                           self.dbformdefinition)

        cursor.execute('select * from sqlite_master \
        where type=\'table\' and name=\'%s\';' % \
                       self.dbitemdefinition)
        tablecount = cursor.fetchall()
        if len(tablecount) == 0:
            cursor.execute('create table %s (iid, fid, title, abbr_title, \
            number, level, order_number, summary, type, default_value, \
            require, active, primary key(iid, fid));' % \
                           self.dbitemdefinition)
        cursor.close()
        connection.commit()
        connection.close()


    def create(self, title=u'untitled', abbr_title=u'', summary=u'', \
               start_date=u'', end_date=u'', active=False):
        fid = u''
        if isinstance(start_date, datetime.datetime):
            start_date = start_date.strftime('%Y-%m-%d %H:%M:%S')
        else:
            if start_date != u'':
                raise TypeError(u'need datetime.datetime, got %r' % \
                                type(start_date))
        if isinstance(end_date, datetime.datetime):
            end_date = end_date.strftime('%Y-%m-%d %H:%M:%S')
        else:
            if end_date != u'':
                raise TypeError(u'need datetime.datetime, got %r' % \
                                type(end_date))
        created_date = datetime.datetime.today().isoformat(' ')
        #created_date = datetime.datetime.today().strftime('%Y-%m-%d %H:%M:%S')
        if not isinstance(active, bool):
            raise TypeError(u'need bool, got %r' % \
                            type(active))
        active = self._pickle(active)

        connection = self._open_db()
        cursor = connection.cursor()
        while True:
            fid = self._generate_id()
            recordcount = self._count_form(cursor, fid)
            if recordcount == 0:
                break
        try:
            cursor.execute('insert into %s (fid, title, abbr_title, \
            summary, start_date, end_date, created_date, active) \
            values(\'%s\', \'%s\', \'%s\', \'%s\', \'%s\', \'%s\', \
            \'%s\', \'%s\');' % \
                           (self.dbformdefinition, fid, title, \
                            abbr_title, summary, start_date, end_date, \
                            created_date, active))
        except:
            raise
        finally:
            cursor.close()
            connection.commit()
            connection.close()

    def list(self):
        connection = self._open_db()
        cursor = connection.cursor()
        cursor.execute('select * from %s \
        order by start_date, end_date, created_date' % \
                       self.dbformdefinition)
        formlist = list()
        for record in cursor.fetchall():
            start_date = record[4]
            if start_date != '':
                start_date = datetime.datetime.strptime(start_date, \
                                                        '%Y-%m-%d %H:%M:%S')
            end_date = record[5]
            if end_date != '':
                end_date = datetime.datetime.strptime(end_date, \
                                                      '%Y-%m-%d %H:%M:%S')
            created_date = record[6]
            import re
            if created_date != '':
                cd = re.split('[\-\s:\.]', created_date)
                created_date = datetime.datetime(int(cd[0]), \
                                                 int(cd[1]), \
                                                 int(cd[2]), \
                                                 int(cd[3]), \
                                                 int(cd[4]), \
                                                 int(cd[5]), \
                                                 int(cd[6]))

            formlist.append({u'fid': record[0], \
                             u'title': record[1], \
                             u'abbr_title': record[2], \
                             u'summary' : record[3], \
                             u'start_date': start_date, \
                             u'end_date': end_date, \
                             u'created_date': created_date, \
                             u'active': self._unpickle(record[7])})
        cursor.close()
        connection.close()
        return formlist
                             

    # internal methods

    def _open_db(self):
        return sqlite3.connect(self.dbpath)

    def _pickle(self, value):
        return base64.encodestring(pickle.dumps(value))

    def _unpickle(self, value):
        if value is None or value == u'None':
            return u''
        else:
            return pickle.loads(base64.decodestring(value))

    def _generate_id(self, digit=8):
        if not isinstance(digit, int):
            raise TypeError(u'need int, got %r' % \
                            type(digit))
        seed = str(random.randint(0, sys.maxint - 1))
        message = hashlib.new('sha512')
        message.update(seed)
        temp_id = message.hexdigest()
        if len(temp_id) > digit:
            return temp_id[0:digit]
        else:
            return temp_id

    def _count_form(self, cursor, fid):
        cursor.execute('select count(*) from %s where fid=\'%s\';' % \
                       (self.dbformdefinition, fid))
        recordcount = cursor.fetchone()
        return recordcount[0]