Clipper2Django

Receita: De Clipper para DJango

Essa receita foi criada após ter feito um sistema em DJango com intenção de substituir um sistema feito em Clipper. Ela segue passos simples, converter arquivos dbf em arquivos csv, criar as tabelas no banco e importar os registros. Junto com a receita vai o código para converter arquivos csv num model do Django.

A linguagem Clipper, foi muito utilizada para fazer sistemas em pequenas e médias empresas e ainda hoje é comum encontrá-los em produção. Porém, é comum também, descobrir que a empresa que forneceu o sistema já nem existe mais, ou pior, ninguém possui os fontes do sistema, esse é meu caso.

Eu sou um programador Python que gosta de usar o framework django, então graças à minha necessidade desenvolvi uma maneira de converter sistemas que usam tabelas (xbase|*.dbf) para django.

Primeiramente transformei tudo em csv com o programa dbfxtrct. Em seguida desenvolvi um script para ler os arquivos csv e gerar um arquivo model.py de acordo com as regras do django. Outro script foi desenvolvido para importar os dados, em seguida é só ajustar os relacionamentos no model.py e começar a escrever suas views e configurar o url.py.

Procedimento

Código

Obtenha um arquivo compactado com os 3 módulos: clipper2django.zip

csv_functions.py

   1 d={'C':'models.CharField(maxlength=%d)',
   2    'D':'models.DateField()',
   3    'N':'models.FloatField(max_digits=%d, decimal_places=%d)'}
   4 
   5 def getFieldList(row):
   6     field_list = []
   7     for field_def in row:
   8         def_list = field_def.split('|')
   9         field_name = def_list[0].lower()
  10         field_type = def_list[1]
  11         field_precision = int(def_list[2])
  12         field_decimal = int(def_list[3])
  13         field_list.append({'field_name':field_name,
  14                            'field_type':field_type,
  15                            'field_precision':field_precision,
  16                            'field_decimal':field_decimal})
  17     return field_list

modelfromcsv.py

   1 import csv
   2 import glob
   3 from csv_functions import d, getFieldList
   4 from getopt import getopt
   5 import sys
   6 
   7 def model(type, digits=0, decimal_places=0, maxlength=0):
   8     if type == 'N':
   9         return d[type] % (digits,decimal_places)
  10     elif type == 'C':
  11         return d[type] % maxlength
  12     else:
  13         return d[type]
  14 
  15 def ModelFromCSV(filename):
  16     ''' Usage : ModelFromcsv('<LOCATION>/<CSVFILE>')
  17     '''
  18     class_template = 'class %s(models.Model):\n'
  19     field_template = '    %s = %s\n'
  20     result_list = []
  21     f=open(filename)
  22     f.seek(0)
  23     class_name = filename.split('/')[-1].split('.')[0].capitalize()
  24     csv_reader = csv.reader(f)
  25     row = csv_reader.next()
  26     field_list = getFieldList(row)
  27 
  28     class_def = class_template % class_name
  29     field_list = [field_template % 
  30                  (x['field_name'],
  31                  model(x['field_type'],
  32                        x['field_precision'],
  33                        x['field_decimal'],
  34                        x['field_precision'])) for x in field_list]
  35     result_list.append([class_def]+field_list)
  36 
  37     return ''.join([''.join(x) for x in result_list])
  38 
  39 def ModelFromFiles(globstring):
  40     file_list = glob.glob(globstring)
  41     result_list = []
  42     for file_name in file_list:
  43         result_list.append(ModelFromCSV(file_name))
  44 
  45     return '\n'.join(result_list)
  46 
  47 def main(args=sys.argv):
  48     optlist, list = getopt(args[1:], ':f:')
  49     for opt in optlist:
  50         if opt[0] == '-f':
  51             globExpr = opt[1]
  52     print '# Model genereted by modelfromcsv\n'
  53     print ModelFromFiles(globExpr)
  54 
  55 if __name__ == '__main__':
  56     main()

insertfromcsv.py

   1 import csv
   2 import glob
   3 from csv_functions import d, getFieldList
   4 from getopt import getopt
   5 import sys
   6 
   7 def InsertFromCSV(filename=''):
   8     insert_template = 'INSERT INTO %s (%s) VALUES (%s);\n'
   9     result_list = []
  10     f=open(filename)
  11     f.seek(0)
  12     table_name = filename.split('/')[-1].split('.')[0].lower()
  13     csv_reader = csv.reader(f)
  14     row = csv_reader.next()
  15     field_list = getFieldList(row)
  16     result_list = []
  17     for row in csv_reader:
  18         value_list = []
  19         field_name_list = []
  20         for idx, field_def in enumerate(field_list):
  21             field_value = insert_field_format(field_def['field_type'],row[idx])
  22             value_list.append(field_value)
  23             field_name_list.append(field_def['field_name'])
  24         result_list.append(insert_template % (table_name,','.join(field_name_list),','.join(value_list)))
  25     return ''.join(result_list)
  26 
  27 def insert_field_format(field_type,field_value):
  28     if field_type == 'N':
  29         return field_value
  30     else:
  31         return '"%s"' % field_value
  32 
  33 def SQLInsertFromFiles(globstring):
  34     file_list = glob.glob(globstring)
  35     result_list = []
  36     for file_name in file_list:
  37         result_list.append(InsertFromCSV(file_name))
  38 
  39     return '\n'.join(result_list)
  40 
  41 def main(args=sys.argv):
  42         optlist, list = getopt(args[1:], ':f:')
  43     for opt in optlist:
  44         if opt[0] == '-f':
  45             globExpr = opt[1]
  46     print '-- SQL - Insert\n'
  47     print SQLInsertFromFiles(globExpr)
  48 
  49 if __name__ == '__main__':
  50     main()

Exemplo de uso

   1 import modelfromcsv
   2 
   3 if __name__ == '__main__':
   4    modelText = modelfromcsv.ModelFromFiles('./csv/*dbfxtract')
   5    insertText = insertfromcsv.InsertFromFiles('./csv/*dbfxtract')
   6    print modelText
   7    print insertText

Para utilizar na linha de comando, supondo que todos os arquivos .dbfxtract estão no subdiretório csv:

ramiro@debianhome:~/src$ python modelfromcsv.py -f './csv/*dbfxtract' > model.py
ramiro@debianhome:~/src$ python insertfromcsv.py -f './csv/*dbfxtract' > model.sql

Volta para CookBook.


Nome do autor da Receita Ramiro Batista da Luz

Clipper2Django (editada pela última vez em 2008-09-26 14:07:40 por localhost)