martes, 30 de agosto de 2011

Django Dia exporter

Today, I adapted an old piece of code I had laying around in my personal GIT. I wrote this code some time ago when I needed to transform an UML diagram I designed, using the awesome DIA, into a Django models file.

All you need to do is take this code and put it somewhere in ${DIA_SHARE_FOLDER}/python/codegen.py (where DIA_SHARE_FOLDER is generally /usr/share/dia), add an import re at the beginning of that file and this:

dia.register_export ("PyDia Code Generation (Django)", 
"py", DjangoRenderer()) 

at the very end (together with the other generators).

The code is:

class DjangoRenderer(ObjRenderer) :
   
    mapp = {"Datetime" : "DateTime"}

    def __init__(self) :

        ObjRenderer.__init__(self)
        self.processed_kls = set([])

    def end_render(self) :
        re_foreign = re.compile(r"[cC]lass\s*(.*).*")
        field_str = "\t%s = models.%sField(%s) %s\n"
        foreign_str = "\t%s = models.ForeignKey('%s'%s) %s\n"

        f = open(self.filename, "w")
        f.write("from django.db import models %s" % ("\n" * 3))
        for sk in self.klasses.keys() :
            parents = self.klasses[sk].parents + self.klasses[sk].templates
            f.write ("class %s (models.Model):\n" % (sk,))
            
            kls_attributes = dict(self.klasses[sk].attributes)
            attributes = kls_attributes.keys()

            if attributes.__len__() == 0:
                f.write("\tpass\n\n")
            else:
                for sa in attributes :

                    comments = ""

                    attr = kls_attributes[sa]
                    value = attr[2] == "" and "None" or attr[2]
                    comments = attr[3]

                    if attr[3]:
                        comments = "#%s" % attr[3].replace('\n', ' ')
                    try:
                        ty, parms = [x.strip() for x in attr[0].split("|")]
                    except ValueError:
                        ty, parms = (attr[0], "")

                    mobj = re_foreign.match(ty)

                    if mobj:
                        foreign_obj = mobj.groups()[0]
                        f.write(foreign_str % (sa, foreign_obj, 
parms, comments))
                    else:
                        ty = ty.capitalize()
                        ty = self.mapp.get(ty, ty)
                        f.write(field_str % (sa, ty, parms, comments))
                else:
                    f.write("\n" * 2)
        f.close()
        ObjRenderer.end_render(self)


Now. The only thing to take into consideration is, when designing in DIA, you have to be a bit more specific in the Type of properties of your classes.

For instance. If you want a property to be of type string, you should specify it as:

Char | max_length=200, null=True.

This tells the exporter that it should construct a

models.CharField(max_length=200, null=True)

If you want to specify a ForeignKey, the type should be:
Class SomeClass
or if you have options (like related_name), this should be:
Class SomeClass | related_name=some.

Hope this serves you somehow.

1 comentario: