Jaymon / prom

A PostgreSQL or SQLite orm for Python
MIT License
22 stars 4 forks source link

Magic Orm that can create orm models straight from the db #95

Open Jaymon opened 4 years ago

Jaymon commented 4 years ago

We did something similar to this in another project:

class DBOrm(Orm):

    table_name = ""
    """This will get set when you use .get_orm_class() so you can query and stuff"""

    _id = _created = _updated = pk = None

    _cache = {"orm": {}, "schema": {}}
    """Caches the schemas generated from the database (see .schema) and orms created
    for individual tables (see .get_orm_class()). These values are cached because
    otherwise they have to be recreated every time you created a child instance
    which would kick off a query to get the fields and to convert those fields to
    Field instances, no sense in doing that since this stuff should change and 
    caching speeds it up considerably"""

    @classproperty
    def schema(cls):
        """overrides schema to generate it from the table information from the db"""
        table_name = cls.table_name
        if table_name in cls._cache["schema"]:
            schema = cls._cache["schema"][table_name]

        else:
            orm_fields = {}
            fields = cls.interface.get_fields(cls.table_name)
            for fn, fopts in fields.items():
                orm_fields[fn] = Field(
                    fopts["field_type"],
                    fopts["field_required"],
                )

            schema = Schema(cls.table_name, **orm_fields)
            cls._cache["schema"][table_name] = schema

        return schema

    @classmethod
    def get_orm_class(cls, table_name):
        """Generate a child class that inherits from this class with the given 
        table_name

        :param table_name: string, the medispan table name
        :returns: a child of this class that can read table_name
        """
        if table_name in cls._cache["orm"]:
            orm_class = cls._cache["orm"][table_name]

        else:
            # https://stackoverflow.com/a/15247892/5006
            orm_class = type(ByteString(table_name), (cls,), {"table_name": table_name})
            cls._cache["orm"][table_name] = orm_class
        return orm_class

It allowed us to have a similar interface for a readonly database we are given, it actually worked surprisingly well, we even had this in the module:

    # Go through the db and export prom.Orm classes for all the tables in the db
    # so they can be imported in other python modules
    for table_name in DBOrm.interface.get_tables():
        logger.debug("Generating Orm class {}.{}".format(__name__, table_name))
        locals()[table_name] = DBOrm.get_orm_class(table_name)

so we could import the table names into other modules like:

from some.module import tablename1, tablename2

Links

Search