Pony ORM define Entity subclass before creating database

525 Views Asked by At

I'm creating a library that contains Bot class. I want it to be able to store messages logs and some other info in the sql database with the help of the pony orm. Idea is for the bot to accept the path to the database and create it or connect to it if it already exists.

Sadly, it seems that with pony I can only define classes after creation of the database object, needing to inherit from database.Entity class to bind my class to the database.

Obvious solution is to define all classes in the Bot class constructor after the creation of the database, but it seems quite ugly in terms of structure, because I plan those classes to be quite large, and wanted to store them in separate files.

Other hypothetical way is to do following (but I don't know whether that functionality is supported):

from pony import orm

class Message(orm.Entity): 
  text = orm.Required(unicode)

class Database(orm.Database):
  def __init__(self, path):
    # super(..).__init__(..)
    # bind Message to self

class Bot(object):
  def __init__(self, path):
    self.database = Database(path)

Yet another possible hypothetical way would be if I could inherit from Database.Entity.

Any ideas? Maybe I can achieve this with another ORMs like SQLAlchemy?

1

There are 1 best solutions below

1
On

You can try this pattern:

from pony import orm


def entities_for_db(db: orm.Database):
    """
    Creates set of entities connected to a specified database.
    :param db: database to which entities should be connected.
    :return: class with database entities.
    """

    class Entities:
        class Language(db.Entity):
            name = orm.Required(str, max_len=128)
            symbol = orm.Required(str, max_len=32)

            @classmethod
            def get_by_symbol(cls, symbol):
                return cls.select(lambda l: l.symbol == symbol).first()

            @classmethod
            def get_or_create(cls, symbol, name):
                return cls.select(lambda l: l.symbol == symbol and l.name == name).first() \
                    or cls(symbol=symbol, name=name)

            def to_dict(self):
                return dict(name=self.name, symbol=self.symbol)

    return Entities


# First sequence run for 2 different databases
db1 = orm.Database(provider='sqlite', filename="test1.sqlite", create_db=True)
db2 = orm.Database(provider='sqlite', filename="test2.sqlite", create_db=True)

db1_entities = entities_for_db(db1)
db2_entities = entities_for_db(db2)

db1.generate_mapping(create_tables=True)
db2.generate_mapping(create_tables=True)

with orm.db_session():
    result1 = db1_entities.Language.get_or_create("en", "English")
    result2 = db2_entities.Language.get_or_create("pl", "Polish")

# Disconnect to let the sequence be run once again
db1.disconnect()
db2.disconnect()

# Second sequence run for the same databases
db1 = orm.Database(provider='sqlite', filename="test1.sqlite", create_db=True)
db2 = orm.Database(provider='sqlite', filename="test2.sqlite", create_db=True)

db1_entities = entities_for_db(db1)
db2_entities = entities_for_db(db2)

db1.generate_mapping(create_tables=True)
db2.generate_mapping(create_tables=True)

with orm.db_session():
    db1_entities.Language.get_or_create("de", "German")
    db2_entities.Language.get_or_create("fr", "French")